PHP - проблема с вложенным mysql_fetch_array () сводит меня с ума - PullRequest
0 голосов
/ 17 февраля 2010

Запрос MySQL:

SELECT title,alias,parent FROM '._prefix.'categories 
WHERE (language = \''._language.'\' || language = \'all\') 
&& status = \'published\'
ORDER BY rank ASC

Результат (от phpMyAdmin):

title    |  alias   |  parent
Home     | home     |    0
Todo     | todo     |    0
Multiuser| todo_mu  |    21
Modulsys | todo_mod |    21

PHP:

while($c = mysql_fetch_array($category_result)) {
    if($c['parent'] == 0) {
        $output .= '<li><a href="'._rewrite_string.$c['alias'].'" title="'.$c['title'].'">'.$c['title'].'</a>';

        $output .= '<ul>';

        mysql_data_seek($category_result,0);

        while($d = mysql_fetch_array($category_result)) {

            $output .= '<li class="space_left"><a href="'._rewrite_string.$c['alias'].'/'.$d['alias'].'" title="'.$d['title'].'">'.$d['title'].'</a>';

            $output .= '</li>';

        }

        $output .= '</ul>';

        $output .= '</li>';
    }
}

Это должно сгенерировать список категорий, подобный этому

кошка 1

  • субкат 1
  • субкат 2

кошка 2

кошка 3

но генерирует что-то подобное

кошка 1

  • кошка 1
  • кошка 2
  • субкат 1
  • субкат 2

использование mysql_fetch_array в другой (вложенный) без использования mysql_data_seek вызывает прерывание после вызова вложенного mysql_fetch_array. выводит только cat1 и ничего более.

пожалуйста, предоставьте мне решение, спасибо

Ответы [ 4 ]

1 голос
/ 17 февраля 2010

Вы получаете ожидаемый результат. Если у вас есть набор результатов a,b,c,d, вы начинаете с a, который является родительской категорией, поэтому он перематывается назад к началу набора и снова перебирает a,b,c,d как подкатегории. Теперь вы находитесь в конце сета, поэтому оба цикла завершатся, поскольку данных больше нет.

То, что вы, вероятно, хотите сделать, - это сначала прочитать все данные в массив PHP, а затем выполнить итерацию по ним и построить некую древовидную структуру. Вы также можете построить свою древовидную структуру непосредственно в цикле mysql_fetch.

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

Еще одна вещь: не используйте mysql_fetch_array, вместо этого используйте mysql_fetch_assoc. В противном случае вы получите числовые и ассоциативные ключи и массив строк, который содержит вдвое больший объем данных, чем следует.

0 голосов
/ 17 февраля 2010

Подумайте, что делает ваш код:

  1. извлекает строку данных в $c и выплевывает заголовок cat1
  2. Заходит во внутренний цикл и многократно извлекает дополнительные данные в $d, выплевывая subcat1, subcat2 и т. Д.
  3. Цикл достигает конца набора результатов и выходит в родительский $c цикл
  4. Больше нет данных для извлечения, поэтому родительский цикл завершается

Синтаксически, если вы хотите убрать все операции с базой данных, вы, по сути, делаете это:

 for ($i = 0; $i < 10; $i++) {   // $c = mysql_fetch_array()
    for ($i = 1; $i < 10; $i++) {  // $d = mysql_fetch_array()
         echo $i;
    }
 }

К тому времени, когда внутренний цикл завершится, $ i равен 10, что убивает внутренний цикл, а затем также убивает внешний цикл.

0 голосов
/ 17 февраля 2010

Вы можете попробовать быстрое и грязное решение, подобное этому:

  1. подготовьте 2 набора результатов с одним и тем же запросом SQL, чтобы вы получили $ category_result и $ category_result2.

  2. Затем используйте $ category_result для внешнего цикла и $ category_result2 для внутреннего цикла.

Надеюсь, это поможет.

0 голосов
/ 17 февраля 2010
$i = 0;
while($c = mysql_fetch_array($category_result)) {
    $parent = $c['parent'];
    $next_row = $i + 1;

    $not_last_row = (mysql_data_seek($category_result, $next_row)); //Move ahead to get next parent or returns false if on last row...
    $next_parent = (!$not_last_row) ? $c['parent'] : FALSE;
    mysql_data_seek($category_result, $i); //Move back to current row

    $open_list = ($parent != $prev_parent);
    $close_list = (($parent > $next_parent) || !$not_last_row); //close list if next parent is smaller number or if this is last row.

    $output .= ($open_list) ? "<ul>" : "";

    $output .= '<li>'.$c['title'].'</li>';

    $output .= ($close_list) ? '</ul>' : "";

    $prev_parent = $parent; //Set this so that on next loop, we can see if they match
    $i++;
}

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

Возможно, вам потребуется добавить что-то, чтобы учесть, что это последняя итерация.

...