web-dev-qa-db-ja.com

再帰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);

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

私はこの結果を得ています:

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および255,20id_hierarchyから欠落しています。

私の間違いはどこにありますか?

3
Kumar

クエリをスライスすると、最初の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

2番目のcte(rt1)の最初のSELECT([root])はこれを返します:

id   hid     parent_hid  hierarchy
11    2         1            2

これは確かにparent_hid = 1を持つ唯一の行です。再帰的CTEは、この単一の値から始まり、一致するものがなくなるまで階層を下っていきます。

これから、2番目の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

parent_hid = 13hid = 13の行)のid = 190に一致するものがないため、190で壊れます。

ルートが1で始まる階層のみを探しているため、壊れます。

期待される出力がどうなるかはわかりませんが、親のない階層(つまり、hid [ルート]にないparent_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

そして、出力は次のようになります。

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

階層を構築するために必要なのは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;

id_hierarchyidは、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
6

この変更されたクエリで

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 
    left join id_hierarchy u on (u.hierarchy=h.hid)
)
select id, hid, str as hierarchy 
from rt1 where id is not null
order by 1

必要な結果が得られました、

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
0
Kumar