2016-08-05 3 views
6

Как я чистил некоторые проблемы в старом зрения в нашей базе данных я наткнулся на это «странный» присоединиться условия:SQL - Последовательные «ON» Заявление

from 
    tblEmails [e] 
    join tblPersonEmails [pe] 
     on (e.EmailID = pe.EmailID) 
    right outer join tblUserAccounts [ua] 
    join People [p] 
     on (ua.PersonID = p.Id) 
    join tblChainEmployees [ce] 
     on (ua.PersonID = ce.PersonID) 
     on (pe.PersonID = p.Id) 

Таблица tblUserAccounts ссылаются как правое внешнее соединение, но по состоянию условие для него не объявляется до тех пор, пока не будут указаны ссылки tblChainEmployees; то есть два последовательных на операциях в строке.

Я не нашел подходящего ответа в любом месте в Интернете, потому что я не знал, что такое присоединяется к.

Итак вопросы:

  1. ли это своего рода "отложенный условный" Join есть имя?
  2. Как это можно переписать для создания того же набора результатов, где операторы на не являются последовательными?
  3. Возможно, это «умное» решение, когда всегда был более простой/понятный способ?
+2

Один из моих сотрудников сделал это хотя бы один раз. Запросы выполняются успешно. Те из нас, кто считает, что ясность и удобочитаемость являются искупительными качествами в программировании, считают, что это умный способ быть глупым. –

+0

Это было сделано для управления порядком соединений. По-видимому, внутренние соединения должны произойти первыми. – shawnt00

ответ

5

(1) Это просто синтаксис, и я никогда не слышал о каком-то специальном имени. Если вы внимательно прочитаете this MSDN article, вы увидите, что (LEFT|RIGHT) JOIN должен быть соединен с оператором ON. Если это не так, выражение внутри анализируется как <table_source>. Вы можете поставить скобки, чтобы сделать его более удобным для чтения:

from 
    tblEmails [e] 
    join tblPersonEmails [pe] 
     on (e.EmailID = pe.EmailID) 
    right outer join 
    (
     tblUserAccounts [ua] 
     join People [p] 
      on (ua.PersonID = p.Id) 
     join tblChainEmployees [ce] 
      on (ua.PersonID = ce.PersonID) 
    ) on (pe.PersonID = p.Id) 

(2) Я бы предпочел LEFT синтаксис, с явными скобками (я знаю, это дело вкуса). Это дает тот же план выполнения:

FROM tblUserAccounts ua 
JOIN People p ON ua.PersonID = p.Id 
JOIN tblChainEmployees ce ON ua.PersonID = ce.PersonID 
LEFT JOIN 
(
    tblEmails e 
    JOIN tblPersonEmails pe ON e.EmailID = pe.EmailID 
) ON pe.PersonID = p.Id 

(3) Да, это умный, как и некоторые C++ выражений (т.е. (i++)*(*t)[0]<<p->a) на интервью. Язык является гибким. Выражения и запросы могут быть сложными, но некоторые «аранжировки» приводят к ухудшению читаемости и ошибкам.

+0

Добавление круглых скобок делает все различия в мире! Это проясняет это полностью. Теперь, если бы я только знал об этом, прежде чем я забил, пытаясь переписать другое мнение несколько месяцев назад. Спасибо, @ Paweł, очень ценится! –

1

Похоже, у вас есть tblEmail и tblPerson со своими независимыми идентификаторами, идентификатором электронной почты и идентификатором (лицом), таблицей привязки tblPersonEmail с действительными парами идентификаторов электронной почты IDID, а затем таблица лиц может иметь 1-1 отношения с UserAccount, которые затем могут иметь 1-1 отношения с chainEmployee, так, чтобы избавиться от RIGHT OUTER JOIN в пользу LEFT, я хотел бы использовать:

FROM 
    ((tblPerson AS p INNER JOIN 
     (tblEmail AS e INNER JOIN 
     tblPersonEmail AS pe ON 
     e.emailID = pe.emailID) ON 
    p.ID = pe.personID) LEFT JOIN 
    tblUserAccount AS ua ON 
    p.ID = ua.personID) LEFT JOIN 
    tblChainEmployee AS ce ON 
    ua.personID = ce.personID 
0

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

Многие люди начинают с запросом, как это:

select ... 
from 
    A a left outer join 
    B b on b.id = a.id left outer join 
    C c on c.id2 = b.id2; 

Взгляд на результаты и понять, что им действительно нужно устранить строки в B, которые не имеют соответствующего C, но если вы попытался сказать where b.id2 is not null and c.id2 is not null, вы победили целую цель левого соединения от A.

Итак, вы пытаетесь это сделать, но это не займет много времени, чтобы понять, что это не сработает. Внутреннее соединение в хвостовой части цепи в основном преобразует оба соединения в внутренние соединения.

select ... 
from 
    A a left outer join 
    B b on b.id = a.id inner join 
    C c on c.id2 = b.id2; 

Проблема кажется простой, но она не работает правильно. По существу, после того, как вы обдумаете какое-то время, вы обнаружите, что вам нужно управлять порядком соединения и сделать внутреннее соединение первым. Таким образом, три запроса ниже являются эквивалентными способами для достижения этого. Первый из них, вероятно, один вы больше знакомы с:

select ... 
from 
    A a left outer join 
    (select * from B b inner join C c on c.id2 = b.id2) bc 
     on bc.id = a.id 

select ... 
from 
    A a left outer join 
    B b inner join 
    C c on c.id2 = b.id2 
     on b.id = a.id 

select ... 
from 
    B b inner join 
    C c on c.id2 = b.id2 right outer join -- now they can be done in order 
    A a on a.id = b.id 

Вы запрос является немного более сложным, но в конечном счете, одни и те же вопросы, пришли в игру, которая, где нечетные вещи пришли. SQL развился, и вы должны помнить, что на платформах не всегда были такие фантастические вещи, как производные таблицы, скалярные подзапросы, CTE, поэтому иногда людям приходилось писать вещи таким образом. И тогда появились графические построители запросов с большим количеством ограничений в более старых версиях таких инструментов, как Crystal Report, которые не учитывали сложные условия соединения ...

Смежные вопросы