WITH RECURSIVE仅返回非递归项

时间:2016-06-09 11:38:08

标签: sql postgresql common-table-expression

我有一个表object,包含以下字段:

  • id:记录ID
  • idobject_parent:对象的父级
  • label:描述对象的任意字符串

构造表内容,以便每个对象都有一个父对象,除了idobject_parent值为null的树的顶部节点。有许多树,每个树都有不同的顶部节点。

给定一个叶子节点,我想得到该树的顶部节点的字段。所以我有以下查询:

with recursive parent_object(id) as (
        select id,idobject_parent, label from object o
    union
        select oe.id, oe.idobject_parent, oe.label from object oe join parent_object pc on (oe.id = pc.idobject_parent) where oe.idobject_parent is not null
)
select id,idobject_parent,label from parent_object where id = 340;

340是我用于此测试的任意叶ID。

问题是这个查询只返回叶子节点本身,即它似乎只是执行非递归的情况。

通过手动执行递归查询并将结果用作下一个的“输入”,我可以看到我正在提升树:

 db=# select oe.id,oe.idobject_parent,oe.label from object oe join (select 340 as id,480 as idobject_parent, 'hello' as label) as pc on (oe.id = pc.idobject_parent) where oe.idobject_parent is not null;
 id  | idobject_parent |   label
-----+-----------------+-----------
 480 |             105 | xxxxxxx
(1 row)

 db=# select oe.id,oe.idobject_parent,oe.label from object oe join (select 480 as id,105 as idobject_parent, 'hello' as label) as pc on (oe.id = pc.idobject_parent) where oe.idobject_parent is not null;
 id  | idobject_parent |         label
-----+-----------------+-----------------------
 105 |             102 | yyyyyyy
(1 row)

 db=# select oe.id,oe.idobject_parent,oe.label from object oe join (select 105 as id,102 as idobject_parent, 'hello' as label) as pc on (oe.id = pc.idobject_parent) where oe.idobject_parent is not null;
 id | idobject_parent | label
----+-----------------+-------
(0 rows)

我的查询有什么问题?为什么我没有得到这个?

 id  | idobject_parent |         label
-----+-----------------+-----------------------
 105 |             102 | yyyyyyy
(1 row)

提前谢谢。

1 个答案:

答案 0 :(得分:1)

不是向下延伸森林(从所有根开始),而是向上走,朝向根。 (这也更有效,因为在选择你想要的路径之前你不必生成所有路径)

-- sample structure
CREATE TABLE thetree
        ( id INTEGER not null primary key
        , parent INTEGER references thetree(id)
        -- , label text
        );

        -- make some data
INSERT INTO thetree(id,parent)
SELECT gs, gs / 3 FROM generate_series(0,20) gs;
UPDATE thetree SET parent = NULL where parent=0;

CREATE UNIQUE INDEX ON thetree(parent,id);

-- SELECT * FROM thetree;

WITH RECURSIVE zzz AS (
        SELECT COALESCE(parent,id) AS root
        , parent AS par
        , id AS me
        , 0::integer AS upsteps
        FROM thetree WHERE id = 17
    UNION ALL
        SELECT COALESCE(t.parent,zzz.root) AS root
        , t.parent AS par
        , zzz.me AS me
        , 1+ zzz.upsteps AS upsteps
        FROM thetree t
        JOIN zzz ON zzz.par = t.id
        )
SELECT *
-- SELECT root,me
FROM zzz
WHERE zzz.par IS NULL -- eliminate partial paths
        ;

仅供参考向下树木行走:

    -- treewalk; starting with roots: downward
WITH RECURSIVE omg AS (
        SELECT id AS root
        , id AS me
        , 0::integer AS upsteps
        FROM thetree WHERE parent IS NULL -- this is the root of a tree
    UNION ALL
        SELECT omg.root AS root
        , t.id AS me
        , 1+ omg.upsteps AS upsteps
        FROM thetree t
        JOIN omg ON t.parent = omg.me
        )
SELECT *
FROM omg
WHERE omg.me = 17
        ;