PHP - 嵌套mysql_fetch_array()的问题让我发疯

时间:2010-02-17 02:02:19

标签: php mysql nested while-loop

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>';
    }
}

这应该生成类似

的类别列表

cat 1

  • subcat 1
  • subcat 2

cat 2

cat 3

但它会产生类似的东西

cat 1

  • cat 1
  • cat 2
  • subcat 1
  • subcat 2

使用mysql_fetch_array到另一个(嵌套)而不使用mysql_data_seek 一旦调用了嵌套的mysql_fetch_array,就会导致中止。它只输出cat1而已。

请提供解决方案,谢谢

4 个答案:

答案 0 :(得分:1)

您获得了预期的结果。如果您有结果集a,b,c,d,则从a开始,这是一个父类别,因此它会回退到集合的开头,并再次作为子类别迭代a,b,c,d。现在你处于集合的末尾,因此两个循环都将退出,因为没有更多的数据。

您可能想要做的是首先将所有数据读入PHP数组,然后迭代它并构建某种树结构。您也可以直接在mysql_fetch循环中构建树结构。

根据您要实现的目标,还有更好的方法来存储数据。值得一读的是如何在SQL中存储树和分层数据。嵌套集可能就是你想要的。

另一件事:不要使用mysql_fetch_array,而是使用mysql_fetch_assoc。否则,最终会得到数字和关联键以及一个包含两倍数据量的行数组。

答案 1 :(得分:0)

$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++;
}

有点匆忙,但我认为这就是你的想法。基本上,如果前一个父项与当前父项不匹配,请打开一个列表。如果当前父级大于下一个父级,请关闭列表。

您可能需要添加一些内容才能将其作为最后一次迭代。

答案 2 :(得分:0)

您可能想尝试这样快速而肮脏的解决方案:

  1. 使用相同的SQL查询准备2个结果集,以便获得$ category_result和$ category_result2。

  2. 然后使用$ category_result作为外部循环,使用$ category_result2作为内部循环。

  3. 希望它有所帮助。

答案 3 :(得分:0)

想想你的代码在做什么:

  1. 将一行数据提取到$c并吐出cat1标题
  2. 进入内部循环并重复将更多数据提取到$d,吐出subcat1,subcat2等。
  3. 循环到达结果集的末尾,并退出到父$c循环
  4. 没有更多要提取的数据,因此父循环退出
  5. 从语法上讲,如果您要删除所有数据库操作,那么基本上就是这样做:

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

    当内循环结束时,$ i为10,这会杀死内循环,然后也会杀死外循环。