Oracle
 sql >> Database >  >> RDS >> Oracle

Utilizzare l'alias di tabella in un'altra query per attraversare un albero

Domanda posta

non puoi fare riferimento a un alias di tabella da una sottoquery in un'altra query allo stesso livello (o in un'altra parte di un UNION interrogazione). Un alias di tabella è visibile solo nella query stessa e nelle sue sottoquery.
Potresti potere fare riferimento alle colonne di output di una sottoquery sullo stesso livello di query con un LATERAL JOIN . Esempio:
Trova gli elementi più comuni nell'array con un gruppo per

Soluzione per un piccolo numero massimo di livelli

Solo per una manciata di livelli (se sai il massimo), puoi utilizzare una semplice query:

  • LEFT JOIN a n-1 istanze della tabella stessa
  • Usa COALESCE e un CASE dichiarazione per definire la radice e l'altezza,
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;

Questo è un SQL standard e dovrebbe funzionare in tutti e 4 gli RDBMS hai taggato.

Soluzione generica per un numero arbitrario di livelli

Utilizzare un CTE ricorsivo come @Ken già consigliato.

  • Nella gamba ricorsiva tieni il bambino per ogni riga, fai avanzare solo il genitore.
  • Nel SELECT esterno , mantieni solo la riga con l'height maggiore per bambino.
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 è specifico di Postgres . Spiegazione:
Selezionare la prima riga in ogni gruppo GROUP BY?

Il resto funzionerebbe in modo simile in Oracle e persino SQLite , ma non in MySQL che non supporta i CTE.

SQL Fiddle dimostrando entrambi.