PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Requête récursive utilisée pour la fermeture transitive

Vous pouvez simplifier à plusieurs endroits (en supposant que acct_id et parent_id sont 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;
  • Les colonnes acct_id , depth , cycle ne sont que du bruit dans votre requête.
  • Le WHERE la condition doit quitter la récursivité une étape plus tôt, avant l'entrée en double du nœud supérieur se trouve dans le résultat. C'était un "off-by-one" dans votre original.

Le reste est du formatage.

Si vous savez le seul cercle possible dans votre graphique est une auto-référence, nous pouvons avoir cela moins cher :

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.

Notez qu'il y aurait des problèmes (au moins jusqu'à la pg v9.4) pour les types de données avec un modificateur (comme varchar(5) ) car la concaténation de tableaux perd le modificateur mais le rCTE insiste sur les types correspondant exactement :

  • Résultats surprenants pour les types de données avec modificateur de type