sql >> Databasteknik >  >> RDS >> Oracle

Använd tabellalias i en annan fråga för att korsa ett träd

Fråga ställd

Du kan inte referera till ett tabellalias från en underfråga i en annan fråga på samma nivå (eller i en annan del av en UNION fråga). Ett tabellalias är bara synligt i själva frågan och underfrågor till den.
Du kunde referera utdatakolumner för en underfråga på samma frågenivå med en LATERAL JOIN . Exempel:
Hitta de vanligaste elementen i array med en grupp av

Lösning för litet maximalt antal nivåer

För bara en handfull nivåer (om du vet). maximalt), kan du använda en enkel fråga:

  • LEFT JOIN till n-1 instanser av själva tabellen
  • Använd COALESCE och en CASE uttalande för att fästa roten och höjden,
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;

Detta är standard SQL och bör fungera i alla fyra RDBMS du taggade.

Generisk lösning för godtyckligt antal nivåer

Använd en rekursiv CTE som @Ken redan har tipsat om.

  • I det rekursiva benet håll barnet för varje rad, flytta bara föräldern.
  • I den yttre SELECT , behåll bara raden med den största height per barn.
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 är specifik för Postgres . Förklaring:
Välj första raden i varje GROUP BY-grupp?

Resten skulle fungera på liknande sätt i Oracle och till och med SQLite , men inte i MySQL som inte stöder CTE.

SQL Fiddle demonstrerar båda.



  1. Ställ in lc_monetary för PostgreSQL

  2. SQLite COUNT

  3. Få alla byggnader inom räckvidd av 5 miles från angivna koordinater

  4. hitta alla namn med mysql-fråga som börjar med bokstaven 'a'