Как перебирать соединенные данные в двух или более вложенных циклах?

Некоторое время назад я спросил вопрос о вложенных циклах на SO и как это было, внутри циклов моего примера были запросы и я получил четкий ответ:

НИКОГДА, НИКОГДА, НИКОГДА не помещайте SQL-запрос в цикл

С тех пор я пробовал, и в основном это работает. Просто нужно приложить усилия и написать запрос, который извлекает все, что вам нужно, сразу.

НО что вы делаете, когда у вас есть набор данных из запроса JOIN, который содержит вложенные данные, которые вам нужно вывести вложенным способом?

Пример соединения из таблиц A и B:

A.a     |  B.a     |  B.b
--------|----------|-------------
fruits  |  banana  |  yellow
fruits  |  apple   |  red
animals |  zebra   |  black&white
animals |  elefant |  gray
animals |  fox     |  red
planets |  earth   |  blue
planets |  mars    |  red

хорошо, теперь я получил все это в массиве или наборе строк, и теперь мне нужно отобразить что-то вроде этого:

фрукты

  • желтый банан
  • красное яблоко

животные

  • черно-белая зебра
  • серый слон
  • рыжая лиса

планеты

  • голубая земля
  • красный Марс

кажется очевидным, что это должно работать, но я уже несколько раз пытался обдумать это, и я просто не могу найти решение.

На данный момент я делаю это по-старому:

query groups

foreach groups
{
    query animals in group
    foreach animal
}

но эй, НИКОГДА, НИКОГДА, НИКОГДА не помещайте sql в цикл. так что мне делать? Я делаю PHP, но я думаю, что это мета-вопрос.


person markus    schedule 22.04.2009    source источник


Ответы (2)


Используйте алгоритм прерывания управления.

Я бы вернул набор результатов точно так, как вы показываете в вопросе:

A.a     |  B.a     |  B.b
--------|----------|-------------
fruits  |  banana  |  yellow
fruits  |  apple   |  red
animals |  zebra   |  black&white
animals |  elefant |  gray
animals |  fox     |  red
planets |  earth   |  blue
planets |  mars    |  red

цикл по всем рядам:

  • при изменении A.a вывести заголовок
  • затем всегда выводить значение B.b + B.a

псевдокод для приложения, вызывающего SQL:

set last_A = null
exec query

loop over result set {
    if last_A == null or fetch_A!=last_A {
        last_A=fetch_A
        display fetch_a
    }
    display fetch_Bb + fetch_Ba
    }
}//loop
person KM.    schedule 22.04.2009
comment
ну, я думал о чем-то подобном, но снова застрял с этим. Я попробую еще раз. - person markus; 23.04.2009
comment
это абсолютно абсолютно работает! пришлось еще немного подумать, потому что я должен был сначала работать над B, а затем отображать A. Но это тоже возможно. Спасибо! - person markus; 23.04.2009
comment
это означает, что я смог объединить более сотни запросов в один :) - person markus; 23.04.2009

Если у вас есть иерархия, "направленный ациклический граф". SQL этого не делает.

Есть и другие вещи из теории графов, которые SQL не делает.

Поскольку SQL этого не делает, правило «никогда не помещать SQL в цикл» выходит из окна.

Вы должны поместить SQL в цикл для иерархий и других проблем соединения графов, связанных с решетками и сетями.

Действительно, для иерархий необходимо использовать рекурсивные циклы для соединения всех элементов иерархии на произвольную глубину.

Если, с другой стороны, вы просто переформатируете результат запроса, чтобы он выглядел как вложенная иерархия, то вы просто переформатируете одиночный набор результатов SQL в то, что выглядит как вложенные списки.

Это будет один выбор со сложными циклами вокруг набора результатов. Один выбор — не в цикле — и сложный цикл для обработки одного набора результатов.

person S.Lott    schedule 22.04.2009
comment
хорошо, я получил первую часть, но вторая часть меня смутила. Если у меня есть именно то, что у меня есть в моем примере, простой дизайн «несколько элементов в группе», где я хочу перебирать группы и внутри групп над элементами. тогда? это возможно или нет? - person markus; 23.04.2009
comment
ты должен быть сумасшедшим! мое приложение отображает данные в таких сетках весь день. в основном он хочет показывать только A.a в первый раз, но каждый раз перечислять B.b+B.a. перебрать набор результатов и заставить php построить html. вам по-прежнему нужен только один набор результатов SQL. - person KM.; 23.04.2009
comment
Да ладно, ребята, запутайте меня :P - person markus; 23.04.2009
comment
возможно, это то, что он имел в виду во второй части, но он такой профессор. Я имею в виду, что вы не получаете 35 000 повторений, задавая простые вопросы и отвечая на них :) - person markus; 23.04.2009
comment
@tharkun, решение простое, не нужны сложные циклы, только простые циклы с простым объяснением - person KM.; 23.04.2009