sql >> Base de Datos >  >> RDS >> Oracle

Usar alias de tabla en otra consulta para atravesar un árbol

Pregunta formulada

Usted no puede hacer referencia a un alias de tabla de una subconsulta en otra consulta en el mismo nivel (o en otro tramo de una UNION consulta). Un alias de tabla solo es visible en la consulta misma y en las subconsultas de la misma.
Usted podría columnas de salida de referencia de una subconsulta en el mismo nivel de consulta con un LATERAL JOIN . Ejemplo:
Encuentre los elementos más comunes en una matriz con un grupo por

Solución para un pequeño número máximo de niveles

Por solo un puñado de niveles (si sabes el máximo), puede usar una consulta simple:

  • LEFT JOIN a n-1 instancias de la propia tabla
  • Usar COALESCE y un CASE declaración para precisar la raíz y la 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 es SQL estándar y debería funcionar en los 4 RDBMS has etiquetado.

Solución genérica para un número arbitrario de niveles

Use un CTE recursivo como @Ken ya aconsejó.

  • En la pierna recursiva mantener al niño para cada fila, solo avance el padre.
  • En el exterior SELECT , solo mantén la fila con la mayor height por niño.
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 es específico de Postgres . Explicación:
¿Seleccionar la primera fila en cada grupo GROUP BY?

El resto funcionaría de manera similar en Oracle e incluso SQLite , pero no en MySQL, que no admite CTE.

SQL Fiddle demostrando ambos.