Puoi semplificare in diversi punti (assumendo acct_id
e parent_id
sono 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;
- Le colonne
acct_id
,depth
,cycle
sono solo rumore nella tua query. - Il
WHERE
condizione deve uscire dalla ricorsione un passaggio prima, prima la voce duplicata dal nodo superiore è nel risultato. Quello era un "off-by-one" nel tuo originale.
Il resto è formattazione.
Se sai l'unico cerchio possibile nel tuo grafico è un riferimento personale, possiamo averlo più economico:
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.
Nota che ci sarebbero problemi (almeno fino a pg v9.4) per i tipi di dati con un modificatore (come varchar(5)
) perché la concatenazione dell'array perde il modificatore ma rCTE insiste sul fatto che i tipi corrispondano esattamente:
- Risultati sorprendenti per i tipi di dati con modificatore di tipo