Псевдонимы подзапросов совпадают с псевдонимами основных запросов

23

У меня есть SQL-запрос, псевдонимы которого совпадают с псевдонимами некоторых его подзапросов.

Например:

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

Это прекрасно работает, так как псевдоним подзапроса, кажется, скрывает основной.

  1. Будет ли это работать так во всех случаях?
  2. Получу ли я когда-нибудь неопределенные результаты?
  3. Если это нормально, как я могу сделать ссылку на основной запрос r?
IcySnow
источник
1
Короткие ответы: «1.Да», «2.Нет» и «3.В таком случае вы не можете (поэтому это не совсем нормально, если вы хотите сделать такую ​​ссылку)»
ypercubeᵀᴹ

Ответы:

15

Для вложенных подзапросов нормально использовать те же псевдонимы, что и в родительском запросе, хотя это может немного смущать читателя кода. Пространство имен для псевдонимов во вложенном подзапросе отделено от пространства имен в родительском. Например, приведенный ниже запрос имеет вложенный подзапрос, в bкотором также используется псевдоним b. Это могло бы сбить с толку программиста, но хорошо с механизмом СУБД:

   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

В коррелированном подзапросе у вас есть доступ к псевдонимам родителя, поэтому псевдонимы должны быть уникальными для родительского запроса и коррелированного подзапроса. Если мы возьмем коррелированный подзапрос, такой как приведенный ниже, у нас будет одно глобальное пространство имен, совместно используемое между родительским запросом и коррелированным подзапросом:

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)

Коррелированный подзапрос не имеет псевдонима, так как он не участвует в объединении как таковом 1 . Ссылки bи b2for barдоступны для подзапроса, так как коррелированные подзапросы совместно используют свое пространство имен для псевдонимов с родителем.


1 Обратите внимание, что оптимизатор может выбрать использование операторов соединения в плане за кулисами, хотя указанная фактическая операция является коррелированным подзапросом, а не объединением с вложенным подзапросом.

ConcernedOfTunbridgeWells
источник
Подзапрос в первом запросе является производной таблицей, и стандартный SQL требует, чтобы ему всегда давалось имя: для этого требования нет логической причины, но в любом случае SQL Server его реализовал, хотя в конкретном примере, который вы выбрали, имя действительно обязательный. Подзапрос во втором запросе не является производной таблицей, поэтому он не требует имени (факт, что это коррелированный подзапрос не имеет значения).
onedaywhen
@onedaywhen - я не могу думать ни о какой ситуации, кроме коррелированного подзапроса, где подзапросу нужен доступ к псевдонимам, используемым в родительском. Вы имели в виду что-то конкретное?
ConcernedOfTunbridgeWells
Я не уверен, что понимаю ваш вопрос. Возможно, мне следует пояснить, что я специально отвечал на ваш комментарий: «У коррелированного подзапроса нет псевдонима, поскольку он не участвует в объединении как таковом». Предполагалось, что в моем ответе будет указано, что правила, касающиеся переменных диапазона (то, что стандарт SQL называет «именами корреляции», а вы называете «псевдонимами») не имеют прямого отношения к их участию (или иным образом) в объединениях.
onedaywhen
Простой пример: SELECT * FROM ( SELECT c FROM T ) AS T2;- нет соединений, нет корреляции, но стандарт SQL требует, чтобы производной таблице была присвоена переменная диапазона ( T2в данном случае).
onedaywhen
3

В ConcernedOfTunbridgeWells вы пишете (выделено мое): «В коррелированном подзапросе у вас есть доступ к псевдонимам родителя, поэтому псевдонимы должны быть уникальными для родительского запроса и коррелированного подзапроса».

Я не верю, что уникальность необходима. Я считаю, что если псевдоним используется в коррелированном подзапросе в качестве имени корреляции, а также псевдоним таблицы во внешнем запросе, псевдоним в подзапросе будет иметь приоритет.

Пример:

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)

Выходные данные равны «3»: таблицы T и U имеют общие 2 и 3, но WHEREпредикат дополнительно фильтрует строки, возвращенные в 3, а 2 не существует в V.

slachterman
источник