U kunt op verschillende plaatsen vereenvoudigen (ervan uitgaande dat acct_id
en parent_id
zijn 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;
- De kolommen
acct_id
,depth
,cycle
zijn slechts ruis in uw zoekopdracht. - De
WHERE
voorwaarde moet de recursie een stap eerder verlaten, voor de dubbele invoer van het bovenste knooppunt staat in het resultaat. Dat was een "off-by-one" in je origineel.
De rest is formatteren.
Als je weet de enige mogelijke cirkel in je grafiek is een zelfreferentie, die kunnen we goedkoper hebben:
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.
Merk op dat er problemen zouden zijn (tenminste tot pg v9.4) voor datatypes met een modifier (zoals varchar(5)
) omdat array-aaneenschakeling de modifier verliest, maar de rCTE dringt erop aan dat typen exact overeenkomen:
- Verrassende resultaten voor gegevenstypen met typemodifier