PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Consulta recursiva usada para fechamento transitivo


Você pode simplificar em vários lugares (assumindo acct_id e parent_id são 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;
  • As colunas acct_id , depth , cycle são apenas ruídos em sua consulta.
  • O WHERE condição tem que sair da recursão um passo antes, antes a entrada duplicada do nó superior está no resultado. Isso foi um "off-by-one" em seu original.

O resto é formatação.

Se você sabe o único círculo possível em seu gráfico é uma auto-referência, podemos ter isso mais barato:
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.

Observe que haveria problemas (pelo menos até pg v9.4) para tipos de dados com um modificador (como varchar(5) ) porque a concatenação de array perde o modificador, mas o rCTE insiste em que os tipos correspondam exatamente:
  • Resultados surpreendentes para tipos de dados com modificador de tipo