Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Use o alias de tabela em outra consulta para percorrer uma árvore

Pergunta feita


Você não pode referenciar um alias de tabela de uma subconsulta em outra consulta no mesmo nível (ou em outra perna de um UNION consulta). Um alias de tabela só é visível na própria consulta e nas subconsultas dela.
Você poderia colunas de saída de referência de uma subconsulta no mesmo nível de consulta com um LATERAL JOIN . Exemplo:
Encontre os elementos mais comuns na matriz com um grupo por

Solução para um pequeno número máximo de níveis


Por apenas alguns níveis (se você saber o máximo), você pode usar uma consulta simples:
  • LEFT JOIN para n-1 instâncias da própria tabela
  • Usar COALESCE e um CASE declaração para definir a raiz e a altura,
SELECT p1.c AS child, COALESCE(p3.p, p2.p, p1.p) AS parent
      ,CASE
          WHEN p3.p IS NOT NULL THEN 3
          WHEN p2.p IS NOT NULL THEN 2
          ELSE 1
       END AS height
FROM   parent p1
LEFT   JOIN parent p2 ON p2.c = p1.p
LEFT   JOIN parent p3 ON p3.c = p2.p
WHERE  p1.c IN (3, 8)
ORDER  BY p1.c;

Este é o SQL padrão e deve funcionar em todos os 4 RDBMS você marcou.

Solução genérica para um número arbitrário de níveis


Use um CTE recursivo como @Ken já aconselhou.
  • Na perna recursiva mantenha a criança para cada linha, avance apenas o pai.
  • No SELECT externo , mantenha apenas a linha com a maior height por criança.
WITH RECURSIVE cte AS (
   SELECT c AS child, p AS parent, 1 AS height
   FROM   parent
   WHERE  c IN (3, 8)

   UNION ALL

   SELECT c.child, p.p AS parent, c.height + 1
   FROM   cte    c
   JOIN   parent p ON p.c = c.parent
   -- WHERE  c.height < 10  -- to safeguard against endless loops if necessary
   )
SELECT DISTINCT ON (child) *
FROM   cte
ORDER  BY child, height DESC;

DISTINCT ON é específico do Postgres . Explicação:
Selecionar a primeira linha em cada grupo GROUP BY?

O resto funcionaria de maneira semelhante no Oracle e até mesmo SQLite , mas não no MySQL que não suporta CTEs.

SQL Fiddle demonstrando ambos.