Alias ​​des sous-requêtes identiques aux alias des requêtes principales

23

J'ai une requête SQL dont les alias sont les mêmes que certains des alias de sa sous-requête.

Par exemple:

select *
from ROOM r
where ...
         (
              select *
              from ROAD r
              where ...
         )

Cela fonctionne très bien, car l'alias de la sous-requête semble masquer le principal.

  1. Cela fonctionnera-t-il de cette façon dans tous les cas?
  2. Vais-je jamais obtenir des résultats indéfinis?
  3. Si c'est OK pour faire cela, comment puis-je faire une référence à la requête principale r?
IcySnow
la source
1
Les réponses courtes sont "1.Oui", "2.Non" et "3. dans ce cas, vous ne pouvez pas (donc ce n'est pas vraiment OK si vous voulez faire une telle référence)"
ypercubeᵀᴹ

Réponses:

15

Il est acceptable que les sous-requêtes imbriquées utilisent les mêmes alias que ceux utilisés dans la requête parent, bien que cela puisse être un peu déroutant pour quelqu'un qui lit le code. L'espace de noms pour les alias d'une sous-requête imbriquée est distinct de l'espace de noms sur le parent. Par exemple, la requête ci-dessous a une sous b- requête imbriquée qui contient également un alias b. Ce serait potentiellement déroutant pour le programmeur mais très bien avec le moteur SGBD:

   select a.foo
          ,b.bar
          ,b.BarCount
      from (select b.bar
                  ,count (*) as BarCount
              from BarTable b
              join OtherTable o
                on b.OtherTableID = o.OtherTableID
             group by b.bar) b
      join Foobar a
        on a.bar = b.bar

Sur une sous-requête corrélée, vous avez accès aux alias du parent, de sorte que les alias doivent être uniques dans la requête parent et la sous-requête corrélée. Si nous prenons une sous-requête corrélée telle que celle ci-dessous, nous avons un seul espace de nom global partagé entre la requête parent et la sous-requête corrélée:

select a.foo
      ,b.bar
  from Foobar a
  join Bar b
    on b.FooBarID = a.FooBarID
 where not exists
       (select 1
          from Bar b2
         where b2.BarCategoryID = b.BarCategoryID
           and b2.BarDate > b.BarDate)

La sous-requête corrélée n'a pas d'alias car elle ne participe pas à une jointure en tant que telle 1 . Les références bet b2for barsont toutes deux disponibles pour la sous-requête, car les sous-requêtes corrélées partagent leur espace de noms pour les alias avec le parent.


1 Notez que l'optimiseur peut choisir d'utiliser les opérateurs de jointure dans le plan en arrière-plan, bien que l'opération réelle spécifiée soit une sous-requête corrélée et non une jointure contre une sous-requête imbriquée.

ConcernedOfTunbridgeWells
la source
La sous-requête dans la première requête est une table dérivée et le SQL standard exige qu'il lui soit toujours donné un nom: il n'y a pas de raison logique à cette exigence mais SQL Server l'a quand même implémentée, bien que dans l'exemple particulier que vous avez choisi, un nom soit en effet Champs obligatoires. La sous-requête de la deuxième requête n'est pas une table dérivée, d'où la raison pour laquelle elle ne nécessite pas de nom (le fait qu'il s'agisse d'une sous-requête corrélée est sans importance).
onedaywhen
@onedaywhen - Je ne peux penser à aucune situation mais à une sous-requête corrélée où la sous-requête a besoin d'accéder aux alias utilisés dans le parent. Aviez-vous quelque chose de spécifique en tête?
ConcernedOfTunbridgeWells
Je ne suis pas sûr de comprendre votre question. Je devrais peut-être préciser que je répondais spécifiquement à votre commentaire: "La sous-requête corrélée n'a pas d'alias car elle ne participe pas à une jointure en tant que telle." Ma réponse était censée faire valoir que les règles concernant les variables de plage (ce que le standard SQL appelle «noms de corrélation» et vous appelez «alias») ne sont pas directement liées à leur participation (ou autre) aux jointures.
onedaywhen
Exemple simple: SELECT * FROM ( SELECT c FROM T ) AS T2;- pas de jointures, pas de corrélation mais le standard SQL requiert que la table dérivée soit affectée à une variable de plage ( T2dans ce cas).
onedaywhen
3

ConcernedOfTunbridgeWells, vous écrivez (soulignement le mien): "Sur une sous-requête corrélée, vous avez accès aux alias du parent, donc les alias doivent être uniques dans la requête parent et la sous-requête corrélée."

Je ne crois pas que l'unicité soit requise. Je crois que, si un alias est utilisé dans une sous-requête corrélée comme nom de corrélation, ainsi qu'un alias de table dans la requête externe, l'alias dans la sous-requête aura priorité.

Exemple:

CREATE TABLE #T (A INT)
CREATE TABLE #U (A INT)
CREATE TABLE #V (A INT)

INSERT INTO #T (A) VALUES (1), (2), (3)
INSERT INTO #U (A) VALUES (2), (3), (4)
INSERT INTO #V (A) VALUES (3), (4), (5)

SELECT
    T1.A
FROM
    #T AS T1
    INNER JOIN #U AS T2 ON T1.A = T2.A
WHERE
    EXISTS (SELECT * FROM #V AS T2 WHERE T1.A = T2.A)

La sortie est "3": les tables T et U ont 2 et 3 en commun, mais le WHEREprédicat filtre davantage les lignes renvoyées à 3 et 2 n'existe pas dans V.

slachterman
la source