sql >> Databasteknik >  >> RDS >> PostgreSQL

Rekursiv fråga används för transitiv stängning

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


  1. TIMESTAMP() Exempel – MySQL

  2. Postgres Query Plan varför raduppskattning är så fel

  3. Kombinera flera underordnade rader till en rad MYSQL

  4. Oracle lagrad procedur med parametrar för IN-sats