Псевдоніми підзапросів такі ж, як псевдоніни основних запитів


23

У мене є SQL-запит, псевдоніми якого збігаються з псевдонімами його підзапиту.

Наприклад:

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

Це працює чудово, оскільки псевдонім підзапиту, схоже, приховує основний.

  1. Чи буде це працювати так у всіх випадках?
  2. Чи коли-небудь я отримаю невизначені результати?
  3. Якщо це правильно, як я можу зробити посилання на основний запит r?

1
Короткі відповіді - "1.Да", "Ні" і "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і b2для, barі обидва доступні для підзапиту, оскільки корельовані підзапити мають спільний простір імен для псевдонімів з батьківським.


1 Зауважте, що оптимізатор може вибрати оператори приєднання в рамках плану за кадром, хоча фактично вказана операція є корельованим підзапитом, а не об'єднанням із вкладеним підзапитом.


Підзапит у першому запиті - це похідна таблиця, а стандартний SQL вимагає, щоб йому завжди було вказано ім'я: немає цієї логічної причини для цієї вимоги, але SQL Server все-таки реалізував її, хоча в конкретному прикладі ви вибрали ім’я справді вимагається. Підзапит у другому запиті не є похідною таблицею, отже, чому він не потребує імені (факт, що це корельований підзапит, не має значення).
день, коли

@onedaywhen - Я не можу думати про будь-яку ситуацію, а лише про співвіднесений підзапит, де підзапросу потрібен доступ до псевдонімів, які використовуються у батьків. Чи мали ви щось на увазі?
ЗанепокоєнийOfTunbridgeWells

Я не впевнений, що розумію ваше запитання. Можливо, я мав би дати зрозуміти, що я спеціально відповідав на ваш коментар: "Корельований підзапит не має псевдоніму, оскільки він не бере участі в об'єднанні як такому". Моя відповідь мала висловити думку про те, що правила щодо змінних діапазонів (те, що стандарт SQL називає "імена кореляції", а ви називаєте "псевдоніми") не мають прямого відношення до їх участі (або іншим чином) у приєднанні.
день, коли

Простий приклад: SELECT * FROM ( SELECT c FROM T ) AS T2;- ніяких приєднань, немає кореляції, але стандарт SQL вимагає, щоб похідній таблиці присвоїли змінну діапазону ( T2у цьому випадку).
день, коли

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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.