MySQL父子关系查询:一次查询选择父级和子级

5

我有一个MySQL表,其中的字段如下:

id            name             parent
1             Fruit             0
2             Meat              0
3             Orange            1
4             Beef              2

父级字段表示上一级的ID。例如水果的ID是1,橙子是其中一种水果,所以其父级是1。

然而,我想要一个高效的MySQL查询,以parent->children->parent->children的格式获取所有记录。我该如何做到这一点?

查询的结果记录应该像这样:

id            name             parent
1             Fruit             0
3             Orange            1
2             Meat              0
4             Beef              2
4个回答

11

您需要进行递归连接,但 MySQL 并不支持。您唯一能做的是确定最大深度级别(在您的情况下为1,因为您有 p->c),通过这个可以确定所需连接的数量:

最大深度级别=自连接数目

SELECT
    p.id as parent_id,
    p.name as parent_id,
    c1.id as child_id,
    c1.name as child_name
FROM 
    my_table p
LEFT JOIN my_table c1
    ON c1.parent = p.id
WHERE
    p.parent=0
例如,如果你的最大深度为3,则需要进行3次自连接:

SELECT
    p.id as parent_id,
    p.name as parent_id,
    c1.id as child_id_1,
    c1.name as child_name_1,
    c2.id as child_id_2,
    c2.name as child_name_2,
    c3.id as child_id_3,
    c3.name as child_name_3
FROM 
    my_table p
LEFT JOIN my_table c1
    ON c1.parent = p.id
LEFT JOIN my_table c2
    ON c2.parent = c1.id
LEFT JOIN my_table c3
    ON c3.parent = c2.id
WHERE
    p.parent=0

谢谢,你知道这个查询的效率吗? - onegun
自从加入后,如果您在“parent”上有索引,它应该很快。 - Stephan
1
WHERE 子句的部分不需要表别名吗?我认为: parent = 0 不会起作用。 - omarjebari

3
这个怎么样?
select * from foods
order by (case parent when 0 then id*1000 else parent*1000+id end), id

这并不是很好的解决方案,如果您有超过1000个与同一父级相关的食品,它将无法工作,但如果您知道这个限制,它应该能够解决问题。


这个很好用,但是 order by 在降序排序时不起作用。 - Dhruv Patadia
你说得对。确实如此。这就是“不太好”的方法的问题所在。你想要一个降序排列,具体是什么?CASE parent WHEN 0 THEN id*1000 + 999 ELSE parent*1000 + id END 如何作为第一个排序表达式? - nurdglaw
1
我想要与问题所需的相同结果,但我希望根据记录时间进行排序。 - Dhruv Patadia
祝贺 @Dhruv Patadia 找到了一个几乎解决了你面临的问题的问题。不幸的是,它似乎不能令您满意,也不能解决您的问题。我很尊重地建议您提出一个详细描述您问题的新问题。 - nurdglaw

1

这里有另一种选项可以获得您想要的结果。您可以通过父级的id将父级和子级分组,然后指示哪个记录是父级(isparent)...就像这样:(此示例假定父记录具有NULL值而不是0的父记录..但它也可以使用0)

SELECT
    IFNULL(parent,id) AS parentid,
    IF(parent IS NULL,1,0) AS isparent,
    name
FROM my_table
ORDER BY
    parentid ASC, <- groups/orders all parentid's together
    isparent DESC, <- orders the parent first
    id DESC <- orders children by their id next

剩下的应该很容易理解,将输出分组等。


为什么这个没有更多的赞?很好而且合理的解决方案! - Cogicero

-1

您可以使用以下带有UNION的查询:

SELECT ID, NAME, PARENT
FROM MY_TABLE AS A,
     MY_TABLE AS B
WHERE A.PARENT != 0 AND
      A.PARENT = B.ID
UNION
SELECT ID, NAME, PARENT
FROM MY_TABLE
WHERE PARENT == 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接