Du kan förenkla på flera ställen (förutsatt acct_id
och parent_id
är INTE 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;
- Kolumnerna
acct_id
,djup
,cykel
är bara brus i din fråga. -
VAR condition måste lämna rekursionen ett steg tidigare, före dubblettposten från toppnoden finns i resultatet. Det var en "av-för-en" i ditt original.
Resten formateras.
Om du vet den enda möjliga cirkeln i din graf är en självreferens, det kan vi ha billigare:
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-fiol.
Observera att det skulle finnas problem (åtminstone upp till sid v9.4) för datatyper med en modifierare (som varchar(5)
) eftersom arraysammansättning förlorar modifieraren men rCTE insisterar på att typerna matchar exakt:
- Overraskande resultat för datatyper med typmodifierare