MySQL:选择行和所有相关行

时间:2016-12-10 21:04:08

标签: php mysql

我有一个categories表设置,如:

ID    CatName      CatParent
1     Websites     NULL
2     Recipes      NULL
3     Programming  1
4     Helpful      3
5     Useless      3
6     Desserts     2

如果我有类别ID,我想查询数据库,按祖先的顺序选择类别和所有父母。每个类别都有一个CatParent,它是父项,如果没有父项,则为NULL

因此,例如,如果我的类别ID为4,我想要一个返回的查询:

array('4','3','1'); // Helpful > Programming > Websites

或者,如果我的类别ID为6:

array('6','2'); // Desserts > Recipes

或类别ID为1:

array('1');

我如何构建此查询?

2 个答案:

答案 0 :(得分:3)

您可以使用left join来获取父类别,但这只有在有限制时才有意义。对于无限的类别深度,我会用PHP做。不过,这是一个示例查询:

select c1.id, c2.id, c3.id
from categories c1 
left join categories c2 on c2.id = c1.catparent
left join categories c3 on c3.id = c2.catparent
where c1.id = 4

如果类别4只有一个父级,则最后一个ID(c3.id)将为NULL。您必须在代码中考虑这一点。

答案 1 :(得分:1)

要实现此目的,您可以创建一个过程。如果使用phpmyadmin,您可以转到数据库,转到SQL并插入以下内容:

DELIMITER //
CREATE PROCEDURE get_parents(IN cid int)
BEGIN
    DECLARE child_id int DEFAULT 0;
    DECLARE prev_id int DEFAULT cid;
    DECLARE loopran int DEFAULT 0; 

    SELECT CatParent into child_id 
    FROM categories WHERE ID=cid ;

    create TEMPORARY  table IF NOT EXISTS temp_table as (select * from categories where 1=0);
    truncate table temp_table;

    WHILE child_id <> 0 OR loopran <> 1 DO
        SET loopran = 1;

        insert into temp_table select * from categories WHERE ID=prev_id;
        SET prev_id = child_id;
        SET child_id=0;
        SELECT CatParent into child_id
        FROM categories WHERE ID=prev_id;
    END WHILE;

    select * from temp_table;
END //

该过程创建一个临时表来存储数据。变量loopran,只是为了确保即使该类别没有子节点,也会返回父节点。

接下来,检索结果:

$id = 5;

$result = "
CALL get_parents($id)
"; // Call the procedure just like as if it were a php function

$query = mysqli_query($conn, $result) or die(mysqli_error($conn));

$x = 0;

while ($row = mysqli_fetch_array($query)) {
    if ($x > 0) echo ", ";
    echo $row['ID'] . " | " . $row['CatParent'];
    $x++;
}

$id = 4返回:4 | 3, 3 | 1

$id = 6返回:6 | 2

$id = 1返回:1 |

$id = 9什么都不返回(如果该行当然不存在。)

  

有一个很大的问题。也就是说,如果你最终进入一个循环,最终指向循环中的前一个id,它将导致无限循环。要解决此问题,您必须退出while循环,条件是它尝试添加已添加的内容。但我认为这绝不会自然而然地发生。 (当然,取决于您使用它的方式以及如何设置ParentID)

来源&amp;来自:@Meherzad - https://stackoverflow.com/a/16514403/2506641