присоединиться к приложению позже - PullRequest
2 голосов
/ 04 марта 2011

У меня есть запрос в следующем формате

select
    *
from
    Table1 t1
    inner join Table2 t2
    inner join Table3 t3 on t2.ID = t3.ID
    on t3.ID = t1.ID

Что я знаю:

  1. Не предоставление последнего условия on приводит к ошибке.
  2. Кроме того, изменение первого условия соединения с on t2.ID = t3.ID на on t1.ID = t2.ID приводит к ошибке, которая t1.ID could not be bound.

Очевидно, что приведенные выше примеры являются произвольными и могут фактически не давать практически полезного результата. Однако, объяснение того, что на самом деле обеспечивает on позже, было бы замечательно.

Спасибо

EDIT Я не пытаюсь изменить вопрос на что-то, что работает, но чтобы понять, что делает MSSQL, когда я его предоставляю.

Ответы [ 4 ]

5 голосов
/ 05 марта 2011

Этот способ написания предложений объединения является одним из способов создания кустарного плана запросов в SQL Server.Оптимизатор запросов обычно рассматривает только объединения, в которых одна сторона объединения является базовым объектом (например, таблица или индексированное представление).

Чтобы создать план, в котором результат одного объединения соединяется непосредственно с результатом другого объединения(пушистый план), нам нужно использовать подсказку FORCE ORDER и использовать либо синтаксис, показанный в вопросе, либо эквивалентную конструкцию с использованием подзапросов (или общих табличных выражений):

-- Four sample tables
DECLARE @T1 TABLE (ID INT PRIMARY KEY);
DECLARE @T2 TABLE (ID INT PRIMARY KEY);
DECLARE @T3 TABLE (ID INT PRIMARY KEY);
DECLARE @T4 TABLE (ID INT PRIMARY KEY);

-- Some data
INSERT  @T1 VALUES (1),(2),(3),(4),(5),(6);
INSERT  @T2 VALUES (1),(2),(3),(4);
INSERT  @T3 VALUES (2),(4),(6);
INSERT  @T4 VALUES (1),(2),(3);

-- Bushy plan
SELECT  *
FROM    @T1
JOIN    @T2
        ON  [@T2].ID = [@T1].ID
JOIN    @T3
JOIN    @T4
        ON  [@T4].ID = [@T3].ID
        ON  [@T4].ID = [@T2].ID
OPTION  (FORCE ORDER);

-- Bushy plan, but note column aliases needed
SELECT  *
FROM    (
        SELECT  *
        FROM    @T1 AS T1
        JOIN    @T2 AS T2
                ON  T2.ID = T1.ID
        ) AS Q1 (ID, ID2)
JOIN    (
        SELECT  *
        FROM    @T3 AS T3
        JOIN    @T4 AS T4
                ON  T4.ID = T3.ID
        ) AS Q2 (ID3, ID4)
        ON Q2.ID4 = Q1.ID2
OPTION  (FORCE ORDER);

В«странный» синтаксис, гнездо объединений и операторы ON не гнездятся ... но это затрудняет чтение TSQL, по крайней мере, на мой взгляд.В редком случае, когда кустистый план будет всегда давать более оптимальный план, чем любое дерево запросов слева или справа, я бы, вероятно, использовал последний синтаксис.

3 голосов
/ 04 марта 2011

Вы можете использовать указанный формат (при условии правильного псевдонима таблицы), , если использовать круглые скобки.

Select ... -- never use Select *
From (Table1 As T1
    Join Table2 As T2
        On T2.ID = T1.ID)
    Join Table3 As T3
        On T3.ID = T1.ID

Однако, с помощью равных объединений (внутренних объединений) это действительно не имеет значения, и его легче читать, если вы не используете скобки. Однако этот формат очень полезен для внешних объединений. Возьмите следующие два примера:

Пример 1

Select ...
From Table1 As T1
    Left Join Table2 As T2
        On T2.T1_ID = T1.ID
    Join Table3 As T3
        On T3.T2_ID = T2.ID

Пример 2

Select ...
From Table1 As T1
    Left Join (Table2 As T2
        Join Table3 As T3
            On T3.T2_ID = T2.ID)
        On T2.T1_ID = T1.ID

Предположим, что в этой ситуации T3.T2_ID является ненулевым внешним ключом для Таблицы2. В примере 1 внутреннее соединение с таблицей 3 будет эффективно отфильтровывать строки, которые были бы нулевыми, поскольку указанный T2.T2_ID не существует в таблице 1. Однако во втором примере соединение между Table2 и Table3 выполняется до обработки Left Join to Table1. Таким образом, мы получим те же строки из Table1 и Table2, что и:

Пример 3

Select ...
From Table1 As T1
    Left Join Table2 As T2
        On T2.T1_ID = T1.ID
2 голосов
/ 04 марта 2011

Предполагая, что вы имели в виду t1, а не t, тогда ваш запрос:

select
    *
from
    Table1 t1
    inner join Table2 t2
    inner join Table3 t3 on t2.ID = t3.ID
    on t3.ID = t1.ID

... можно сделать более понятным, добавив скобки, которые ему на самом деле не нужны:

select
    *
from
    Table1 t1
      inner join 
        (Table2 t2 inner join Table3 t3 on t2.ID = t3.ID) on t3.ID = t1.ID

Фактически, вы явно говорите: «присоедините t2 к t3, а затем присоедините t1 к этому».

Это помогает?

0 голосов
/ 04 марта 2011

Прежде всего - вы не определяете, что т

Таблица 1 имеет псевдоним t1 Таблица 2 является псевдонимом T2 Таблица 3 является псевдонимом T3

Но нет простого т.

Во-вторых, вы делаете не соединение t1 с t2, а с t1 до t3, а затем от t3 до t2. Это будет работать. Если между t1 и t2 существует связь (t1.ID = t2.ID), то этот оператор on должен непосредственно следовать за внутренним оператором соединения для t2:

select
    *
from
    Table1 t1
    inner join Table3 t3 on t1.ID = t3.ID
    inner join Table2 t2 on t3.ID = t2.ID

ОБНОВЛЕНИЕ (в зависимости от вашего обновления) Являются ли t1.ID, t2.ID и t3.ID одинаковым типом данных?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...