Zjednodušit můžete na několika místech (za předpokladu, že acct_id
a parent_id
NOT NULL
):
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE g.acct_id <> ALL(sg.path)
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
- Sloupce
acct_id
,depth
,cycle
jsou ve vašem dotazu jen šumy. WHERE
podmínka musí ukončit rekurzi o jeden krok dříve, před duplicitní záznam z horního uzlu je ve výsledku. To bylo ve vašem originálu „neza sebou“.
Zbytek je formátování.
Pokud víte jediný možný kruh ve vašem grafu je autoreference, můžeme to mít levnější:
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path, acct_id <> parent_id AS keep_going
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id, g.acct_id <> g.parent_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE sg.keep_going
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
SQL Fiddle.
U datových typů s modifikátorem (jako varchar(5)
by mohly nastat problémy (alespoň do pg v9.4) ), protože zřetězení pole ztrácí modifikátor, ale rCTE trvá na tom, aby se typy přesně shodovaly:
- Překvapivé výsledky pro datové typy s modifikátorem typu