查询邻接列表中最远的孩子

时间:2013-02-04 22:23:02

标签: sql postgresql recursive-query adjacency-list

所以我有一个SQL查询来检索邻接列表中给定节点的所有子节点。

WITH    RECURSIVE
        q AS
        (
        SELECT  id, name
        FROM    categories h
        WHERE   id = 11846801
        UNION ALL
        SELECT  hc.id, hc.name
        FROM    q
        JOIN    categories hc
        ON      hc.parent = q.id
        )
SELECT  name
FROM    q

有没有办法修改此查询以返回只是节点的底层?我不能只指定给定的级别,因为每条路径可能有不同的深度。

3 个答案:

答案 0 :(得分:3)

解释1

“所有离开的节点从一开始就具有最长的路径。”

一种方法是计算下降的水平,只返回底部的成员:

WITH    RECURSIVE
        q AS
        (
        SELECT  id, name, 0 AS lvl
        FROM    categories h
        WHERE   id = 11846801
        UNION ALL
        SELECT  hc.id, hc.name, q.lvl + 1
        FROM    q
        JOIN    categories hc
        ON      hc.parent = q.id
        )
SELECT  id, name
FROM    q
WHERE   lvl = (SELECT max(lvl) FROM q)

解释2

“所有离开节点。”

WITH    RECURSIVE
        q AS
        (
        SELECT  id, name, parent
        FROM    categories h
        WHERE   id = 11846801
        UNION ALL
        SELECT  hc.id, hc.name, hc.parent
        FROM    q
        JOIN    categories hc
        ON      hc.parent = q.id
        )
SELECT  id, name
FROM    q
WHERE   NOT EXISTS (SELECT 1 FROM q q1 WHERE q1.parent = q.id)

检查q比基表更快。

答案 1 :(得分:2)

底层的东西绝不是父母。因此,您可以添加以下where子句:

where id not in (select parent from categories)

实际上,在Postgres中,not in可能不是最有效的方法。所以,这可能更有效:

where not exists (select 1 from categories c where c.parent = q.id)

答案 2 :(得分:1)

只是迭代Gordon Linoff's answer。他的查询工作很有意义,但前提是没有NULL值。因此,为了解决这个问题,需要一个额外的where子句。

SELECT id WHERE id NOT IN (SELECT parent FROM categories WHERE parent IS NOT NULL);

我今天才发现这件事。 (并没有足够的代表评论)

  

为了符合SQL标准,IN不仅在左侧的表达式为NULL时返回NULL,而且如果在列表中找不到匹配且列表中的一个表达式为NULL,则返回NULL。

参考 http://dev.mysql.com/doc/refman/5.6/en/comparison-operators.html#function_in