PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Query ricorsiva utilizzata per la chiusura transitiva

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