2016-08-05 63 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. 難道這種「遞延有條件」加入有名字嗎?
  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與自己的獨立ID,emailID和ID(人),一個鏈接表tblPersonEmail與有效的電子郵件ID/ID對,然後人表可能有一個1-1與UserAccount,然後關係可能有chainEmployee一個1-1的關係,所以要擺脫右外贊成LEFT JOIN的,我會用:

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這樣的舊版本工具中存在很多限制,這些工具不允許複雜的連接條件...