T-SQL基礎(二)之關聯查詢
在上篇博文中介紹了T-SQL查詢的基礎知識,本篇主要介紹稍微複雜的查詢形式。
表運算子
表運算子的作用是把為其提供的表作為輸入,經過邏輯查詢處理,返回一個表結果。SQL Server支援四個表運算子:JOIN、APPLY、PIVOT、UNPIVOT,其中JOIN是標準SQL中的運算子,APPLY、PIVOT和UNPIVOT是T-SQL的擴充套件。
JOIN:聯接查詢時使用
APPLY:用於FROM子句中,分為 CROSS APPLY
和 OUTER APPLY
兩種形式
PIVOT:用於行轉列
UNPIVOT:用於列傳行
聯接查詢
聯接查詢分為外聯接、內聯接、交叉聯接,三者的區別在於如何應用邏輯查詢處理階段:
ON ON
內部行 & 外部行
內部行指的是基於謂詞ON與另一側匹配的行,外部行則是未匹配的行,外部行用NULL進行填充。內聯接結果集僅保留內部行,外聯接結果集返回內部行和外部行。
笛卡爾乘積
將一個輸入表的每一行與另一個表的所有行匹配,即, 如果一張表有m行a列,另一張表n行b列,笛卡爾乘積後得到的表有m n行,a+b列 *。由此可以看出,對於資料量較大的表進行關聯的話,會得到一張資料量更大的表,會有可能造成記憶體溢位的。
以下是網路上關於笛卡爾乘積的解釋:
在數學中,兩個集合X和Y的 ofollow,noindex" target="_blank">笛卡兒 積(Cartesian product),又稱直積,表示為X × Y,第一個物件是X的成員而第二個物件是Y的所有可能有序對的其中一個成員。假設集合A=a, b,集合B=0, 1, 2,則兩個集合的笛卡爾積為(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)。類似的例子有,如果A表示某學校學生的集合,B表示該學校所有課程的集合,則A與B的笛卡爾積表示所有可能的選課情況。A表示所有聲母的集合,B表示所有韻母的集合,那麼A和B的笛卡爾積就為所有可能的漢字全拼。
舉例如下:
USE WJChi; SELECT * FROM dbo.UserInfo; SELECT * FROM dbo.UAddress; SELECT * FROM dbo.UserInfo CROSS JOIN dbo.UAddress;
得到結果集如下:
交叉聯接
SQL中使用 CROSS JOIN
語句進行交叉聯接查詢,在邏輯處理上,交叉聯接是最為簡單的聯接型別,它只獲取表的笛卡爾乘積。
交叉聯接兩種寫法:
USE WJChi; -- 使用CROSS JOIN,推薦使用這種方式 SELECT * FROM dbo.UserInfo CROSS JOIN dbo.UAddress; -- 不使用CROSS JOIN SELECT * FROM dbo.UserInfo,dbo.UAddress;
內聯接
SQL中使用 INNER JOIN...ON...
語句進行內聯接查詢, INNER
關鍵字可選。內聯接的邏輯處理分為兩步:
ON
與交叉聯接一樣,內聯接有兩種寫法:
USE WJChi; -- 使用JOIN,推薦使用這種方式 SELECT * FROM dbo.UAddress JOIN dbo.UserInfo ON UserInfo.UAddressId = UAddress.Id; -- 不使用JOIN,與交叉聯接類似,但比交叉聯接多了WHERE條件 SELECT * FROM dbo.UAddress,dbo.UserInfo WHERE UserInfo.UAddressId = UAddress.Id;
外聯接
外聯接分為左外聯接: LEFT OUT JOIN
、右外聯接: RIGHT OUT JOIN
和全聯接: FULL OUT JOIN
,其中, OUT
關鍵字是可選的。相比於交叉聯接和內聯接,外聯接則最為複雜。外聯接邏輯處理分為三步:
ON
LEFT JOIN & RIGHT JOIN
LEFT JOIN
獲取的結果集中保留了左表(LEFT JOIN左側的表)中的所有資料,及右表中滿足篩選條件的資料。右表中不滿足篩選條件的空行(外部行)則用NULL值填充。
RIGHT JOIN
與 LEFT JOIN
作用相反。
示例程式碼如下,表UserInfo中有4條資料,表UAddress中有三條資料:
USE WJChi; SELECT * FROM dbo.UAddress LEFT JOIN dbo.UserInfo ON UserInfo.UAddressId = UAddress.Id; SELECT * FROM dbo.UAddress RIGHT JOIN dbo.UserInfo ON UserInfo.UAddressId = UAddress.Id;
查詢結果如下:

FULL JOIN
FULL JOIN
的結果是取 LEFT JOIN
和 RIGHT JOIN
查詢結果集的並集
USE WJChi; SELECT * FROM dbo.UAddress FULL JOIN dbo.UserInfo ON UserInfo.UAddressId = UAddress.Id;
查詢結果如下:

ON & WHERE
前面說到:內聯接結果集僅保留內部行,外聯接結果集返回內部行和外部行。換句話說,外聯接中 ON
子句的作用是進行表之間關聯,如果外聯接需要對結果集做進一步的篩選的話不能使用 ON...AND...
語句,而要使用 WHERE
條件。示例如下:
USE WJChi; -- 內聯接使用ON...AND...篩選資料 SELECT * FROM dbo.UserInfo AS UI JOIN dbo.UAddress AS UA ON UA.Id = UI.UAddressId -- 獲取Name為xfh的資料 AND UI.Name='xfh'; -- 外聯接使用ON...AND...篩選資料 SELECT * FROM dbo.UserInfo AS UI LEFT JOIN dbo.UAddress AS UA ON UA.Id = UI.UAddressId -- 獲取Name為xfh的資料,無效 AND UI.Name='xfh'; -- 外聯接使用WHERE對結果集進行篩選 SELECT * FROM dbo.UserInfo AS UI LEFT JOIN dbo.UAddress AS UA ON UA.Id = UI.UAddressId WHERE UI.Name='xfh';
輸出結果如下:

複合聯接
複合聯接是指謂詞涉及表中多個欄位的聯接,即,關聯條件使用 ON...AND...
的形式。
自聯接
同一張表的多個例項之間相互聯接,稱為自聯接。所有基本聯接型別(內聯接、外聯接、交叉聯接)支援。
USE WJChi; SELECT * FROM dbo.UserInfo AS U1 CROSS JOIN dbo.UserInfo AS U2;
自聯接中要為表名指定別名,否則結果集中的列名都將不明確。
相等聯接 & 不等聯接
當聯接條件使用相等運算子時稱為相等聯接,否則稱為不等聯接:
USE WJChi; -- 相等聯接 SELECT * FROM dbo.UAddress FULL JOIN dbo.UserInfo ON UserInfo.UAddressId = UAddress.Id; -- 不等聯接 SELECT * FROM dbo.UAddress FULL JOIN dbo.UserInfo ON UserInfo.UAddressId <> UAddress.Id;
多聯接查詢
超過兩張表進行關聯查詢即為多聯接查詢。通常,當SQL中出現多個表運算子時,從左到右進行邏輯處理,前一個聯接的結果會作為下一個聯接的左側輸入。SQL Server也常常出於優化查詢的目的,在實際處理查詢過程中對聯接進行重新排序,但這不會影響到處理結果集的正確性。
不建議超過三張表進行關聯,過多的表關聯會使SQL變得複雜,難以維護且影響效能
小結
過多的表聯接會讓SQL邏輯變得複雜,對查詢效能產生負面影響,且難以維護。
SQL(任何程式碼)的書寫應將語義清晰作為第一追求,而不是為了“炫技”寫一些別人難以理解的程式碼。
StackOverflow 中扣出的一張圖片,可以概述外聯接和內聯接查詢:

推薦閱讀
What is the difference between “INNER JOIN” and “OUTER JOIN”?