Du kan forenkle flere steder (forudsat acct_id
og parent_id
er IKKE 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;
- Kolonnerne
acct_id
,dybde
,cyklus
er bare støj i din forespørgsel. HVOR betingelse skal forlade rekursionen et trin tidligere, før duplikatindtastningen fra den øverste node er i resultatet. Det var en "off-by-one" i din original.
Resten formateres.
Hvis du ved det den eneste mulige cirkel i din graf er en selvreference, det kan vi få billigere:
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.
Bemærk, at der ville være problemer (i det mindste op til side v9.4) for datatyper med en modifikator (såsom varchar(5)
) fordi array-sammenkædning mister modifikationen, men rCTE insisterer på, at typer matcher nøjagtigt:
- Overraskende resultater for datatyper med typemodifikator