为什么我的递归 CTE 中缺少某些行?

Kum*_*mar 3 postgresql cte

这些是我的 2 个表id_hierarchyhierarchy_link

CREATE TABLE id_hierarchy
(
    id integer NOT NULL,
    hierarchy integer
);
insert into id_hierarchy values (11,2),(22,3),(44,5),(77,8),(170,11),
(190,13),(240,18),(255,20);

CREATE TABLE hierarchy_link
(
    hid integer NOT NULL,
    parent_hid integer
);
insert into hierarchy_link values (1,0),(2,1),(3,2),(5,3),(8,5),(11,8),
(13,11),(15,13),(18,15),(20,18);
Run Code Online (Sandbox Code Playgroud)

id_hierarchy.hierarchy=hierarchy_link.hid

对于以下 CTE 查询:

with recursive rt1 as(
    select id,hid,parent_hid||'->'||hid as str 
    from rt2 
    where rt2.parent_hid=1
    union
    select t.id,t.hid,s.str||'->'||t.hid as str 
    from rt2 t 
    inner join rt1 s on (s.hid=t.parent_hid)
),
rt2 as (
    select id, hid, parent_hid, hierarchy 
    from hierarchy_link h 
    inner join id_hierarchy u on (u.hierarchy=h.hid)
)
select id, hid, str as hierarchy 
from rt1 
order by 1
Run Code Online (Sandbox Code Playgroud)

我得到这个结果:

id;  hid; hierarchy
11;  2;   "1->2"
22;  3;   "1->2->3"
44;  5;   "1->2->3->5"
77;  8;   "1->2->3->5->8"
170; 11;  "1->2->3->5->8->11"
190; 13;  "1->2->3->5->8->11->13"
Run Code Online (Sandbox Code Playgroud)

中缺少行240,18和。255,20id_hierarchy

我的错误在哪里?

Jul*_*eur 6

如果我们对您的查询进行切片,第一个 cte ( rt2) 将返回:

id   hid     parent_hid  hierarchy
11    2         1            2
22    3         2            3
44    5         3            5
77    8         5            8
170  11         8           11
190  13         11          13
240  18         15          18
255  20         18          20
Run Code Online (Sandbox Code Playgroud)

SELECT第二个 cte ( rt1) 中的第一个([root] ) 返回:

id   hid     parent_hid  hierarchy
11    2         1            2
Run Code Online (Sandbox Code Playgroud)

这确实是唯一的一行parent_hid = 1。递归 CTE 以这个单一值开始,一直沿着层次结构向下,直到不再有匹配项。

由此看来,第二SELECT递归地加入rt2rt1rt1.hid = rt2.parent_id

id   hid     parent_hid  hierarchy
11    2         1            2 -+                1->2                   => start 
22    3         2            3 -+ -+             1->2->3                => previous + 3
44    5         3            5    -+ -+          1->2->3->5             => previous + 5
77    8         5            8       -+ -+       1->2->3->5->8          => previous + 8
170  11         8           11          -+ -+    1->2->3->5->8->11      => previous + 11
190  13         11          13             -+    1->2->3->5->8->11->13  => breaks here
240  18         15          18
255  20         18          20
Run Code Online (Sandbox Code Playgroud)

它在 190 处中断,因为parent_hid = 13where hid = 13(row for id = 190)没有匹配项。

它中断了,因为您只是在寻找以 1 为根的层次结构。

我不确定您的预期输出应该是什么,但是如果您正在寻找没有父级(即parent_hid不在hid[根] 中)的层次结构,您也会得到层次结构15->18->20

替换where rt2.parent_hid=1WHERE NOT EXISTS (SELECT 1 FROM rt2 WHERE hid = r.parent_hid)和起始根将是:

id  hid hierarchy
11  2   1->2
240 18  15->18
Run Code Online (Sandbox Code Playgroud)

输出将是:

id  hid hierarchy
11  2   1->2
22  3   1->2->3
44  5   1->2->3->5
77  8   1->2->3->5->8
170 11  1->2->3->5->8->11
190 13  1->2->3->5->8->11->13
240 18  15->18
255 20  15->18->20
Run Code Online (Sandbox Code Playgroud)

似乎只hierarchy_link需要建立层次结构。因此 rt2 应该被删除:

;WITH rt1 AS (
    SELECT hid, parent_hid, CAST(parent_hid as varchar(50)) + '->' + CAST(hid as varchar(50)) as [str] 
    FROM hierarchy_link r
    WHERE r.parent_hid = 1
    UNION ALL
    SELECT l.hid, l.parent_hid, CAST(r.[str] as varchar(50)) + '->' + CAST(l.hid as varchar(50)) as [str] 
    FROM hierarchy_link l
    INNER JOIN rt1 r ON r.hid = l.parent_hid
)
SELECT h.id, r.hid, r.[str] as hierarchy 
FROM rt1 r
INNER JOIN id_hierarchy h ON h.hierarchy = r.hid;
Run Code Online (Sandbox Code Playgroud)

一旦层次结构准备好,idfromid_hierarchy只会在最后添加rt1

id  hid hierarchy
11  2   1->2
22  3   1->2->3
44  5   1->2->3->5
77  8   1->2->3->5->8
170 11  1->2->3->5->8->11
190 13  1->2->3->5->8->11->13
240 18  1->2->3->5->8->11->13->15->18
255 20  1->2->3->5->8->11->13->15->18->20
Run Code Online (Sandbox Code Playgroud)