Oracle
 sql >> Base de données >  >> RDS >> Oracle

Utiliser un alias de table dans une autre requête pour parcourir un arbre

Question posée

Vous ne pouvez pas référencer un alias de table d'une sous-requête dans une autre requête au même niveau (ou dans une autre branche d'une UNION requête). Un alias de table n'est visible que dans la requête elle-même et ses sous-requêtes.
Vous pourriez référencer les colonnes de sortie d'une sous-requête au même niveau de requête avec un LATERAL JOIN . Exemple :
Rechercher les éléments les plus courants dans un tableau avec un groupe par

Solution pour un petit nombre maximum de niveaux

Pour seulement une poignée de niveaux (si vous savez le maximum), vous pouvez utiliser une requête simple :

  • LEFT JOIN à n-1 instances de la table elle-même
  • Utilisez COALESCE et un CASE déclaration pour cerner la racine et la hauteur,
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;

Ceci est du SQL standard et devrait fonctionner dans les 4 SGBDR vous avez tagué.

Solution générique pour un nombre arbitraire de niveaux

Utilisez un CTE récursif comme @Ken déjà conseillé.

  • Dans la jambe récursive gardez l'enfant pour chaque ligne, avancez uniquement le parent.
  • Dans le SELECT externe , ne conservez que la ligne avec la plus grande height par enfant.
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 est spécifique à Postgres . Explication :
 Sélectionner la première ligne de chaque groupe GROUP BY ?

Le reste fonctionnerait de la même manière dans Oracle et même SQLite , mais pas dans MySQL qui ne prend pas en charge les CTE.

SQL Fiddle démontrant les deux.