轉載來源:https://www.jb51.net/article/191585.htm
概述
爲什麼使用集合運算:
在集合運算中比聯接查詢和EXISTS/NOT EXISTS更方便。
並集運算(UNION)
並集:兩個集合的並集是一個包含集合A和B中所有元素的集合。
在T-SQL中。UNION集合運算可以將兩個輸入查詢的結果組合成一個結果集。需要注意的是:如果一個行在任何一個輸入集合中出現,它也會在UNION運算的結果中出現。T-SQL支持以下兩種選項:
(1)UNION ALL:不會刪除重複行
1
2
3
4
|
-- union allselect country, region, city from hr.Employees union all select country, region, city from sales.Customers; |
(2)UNION:會刪除重複行
1
2
3
4
|
-- union select country, region from hr.Employees union select country, region from sales.Customers; |
交集運算(INTERSECT)
交集:兩個集合(記爲集合A和集合B)的交集是由既屬於A,也屬於B的所有元素組成的集合。
在T-SQL中,INTERSECT集合運算對兩個輸入查詢的結果取其交集,只返回在兩個查詢結果集中都出現的行。
INTERSECT集合運算在邏輯上會首先刪除兩個輸入集中的重複行,然後返回只在兩個集合中中都出現的行。換句話說:如果一個行在兩個輸入集中都至少出現一次,那麼交集返回的結果中將包含這一行。
例如,下面返回既是僱員地址,又是客戶地址的不同地址:
1
2
3
4
|
-- intersect select country, region, city from hr.Employees intersect select country, region, city from sales.Customers; |
這裏需要說的是,集合運算對行進行比較時,認爲兩個NULL值相等,所以就返回該行記錄。
差集運算(EXCEPT)
差集:兩個集合(記爲集合A和集合B)的由屬於集合A,但不屬於集合B的所有元素組成的集合。
在T-SQL中,集合之差使用EXCEPT集合運算實現的。它對兩個輸入查詢的結果集進行操作,反會出現在第一個結果集中,但不出現在第二個結果集中的所有行。
EXCEPT結合運算在邏輯上首先刪除兩個輸入集中的重複行,然後返回只在第一個集合中出現,在第二個結果集中不出現的所有行。換句話說:一個行能夠被返回,僅當這個行在第一個輸入的集合中至少出現過一次,而且在第二個集合中一次也沒出現過。
此外,相比UNION和INTERSECT,兩個輸入集合的順序是會影響到最後返回結果的。
例如,藉助EXCEPT運算,我們可以方便地實現屬於A但不屬於B的場景,下面返回屬於員工抵制,但不屬於客戶地址的地址記錄:
1
2
3
4
|
-- except select country, region, city from hr.Employees except select country, region, city from sales.Customers; |
集合運算優先級
SQL定義了集合運算之間的優先級:INTERSECT最高,UNION和EXCEPT相等。
換句話說:首先會計算INTERSECT,然後按照從左至右的出現順序依次處理優先級相同的運算。
1
2
3
4
5
6
|
-- 集合運算的優先級 select country, region, city from Production.Suppliers except select country, region, city from hr.Employees intersect select country, region, city from sales.Customers; |
上面這段SQL代碼,因爲INTERSECT優先級比EXCEPT高,所以首先進行INTERSECT交集運算。因此,這個查詢的含義是:返回沒有出現在員工地址和客戶地址交集中的供應商地址。
集合運算的優先級
1.INTERSECT>UNION=EXCEPT
2.首先計算INTERSECT,然後從左到右的出現順序依次處理優先級的相同的運算。
3.可以使用圓括號控制集合運算的優先級,它具有最高的優先級。
在排序函數的OVER字句中使用ORDER BY ( SELECT <常量> )可以告訴SQL Server不必在意行的順序。
使用表表達式避開不支持的邏輯查詢處理
集合運算查詢本身並不持之除ORDER BY意外的其他邏輯查詢處理階段,但可以通過表表達式來避開這一限制。
解決方案就是:首先根據包含集合運算的查詢定義一個表表達式,然後在外部查詢中對錶表達式應用任何需要的邏輯查詢處理。
(1)例如,下面的查詢返回每個國家中不同的員工地址或客戶地址的數量:
1
2
3
4
|
select country, COUNT(*) as numlocations from (select country, region, city from hr.Employees union select country, region, city from sales.Customers) as Ugroup by country; |
(2)例如,下面的查詢返回由員工地址爲3或5的員工最近處理過的兩個訂單:、
1
2
3
4
5
6
7
8
9
10
11
|
select empid,orderid,orderdate from ( select top (2) empid,orderid,orderdate from sales.Orders where empid=3 order by orderdate desc ,orderid desc ) as D1 union all select empid,orderid,orderdate from ( select top (2) empid,orderid,orderdate from sales.Orders where empid=5 order by orderdate desc ,orderid desc ) as D2; |
轉載來源二:https://www.cnblogs.com/kissdodog/archive/2013/06/24/3152743.html
爲了配合測試,特地建了兩個表,並且添加了一些測試數據,其中重複記錄爲東吳的人物。
表:Person_1魏國人物
表:Person_2蜀國人物
A、Union形成並集
Union可以對兩個或多個結果集進行連接,形成“並集”。子結果集所有的記錄組合在一起形成新的結果集。
1、限定條件
要是用Union來連接結果集,有4個限定條件。
(1)、子結果集要具有相同的結構。
(2)、字結果集的列數必須相同。
(3)、子結果集對應的數據類型必須可以兼容。
(4)、每個子結果集不能包含order by和compute子句。
2、語法形式
select_statement union [all] select_statement
all代表最終的結果集中將包含所有的行,而不能刪除重複行。
示例:
SELECT Name FROM Person_1 UNION SELECT Name FROM Person_2
生成的結果爲:
注意到重複記錄,孫權與周瑜僅僅顯示了一個。下面來將UNION替換成UNION ALL看看是什麼結果:
SELECT Name FROM Person_1 UNION ALL SELECT Name FROM Person_2
注意到重複記錄,孫權與周瑜出現了兩次,這就是UNION ALL 與 UNION的不同之處。
B、Except形成差集
Except可以對兩個或多個結果集進行連接,形成“差集”。返回左邊結果集合中已經有的記錄,而右邊結果集中沒有的記錄。
限定條件:
1、子結果集要具有相同的結構。
2、子結果集的列數必須相同。
3、子結果集對應的數據類型必須可以兼容。
4、每個子結果集不能包含order by 和 compute子句。
語法形式:
select_statement except select_statement
自動刪除重複行。
示例:
SELECT Name FROM Person_1 EXCEPT SELECT Name FROM Person_2
結果:
留意到表Person_2有的,孫權周瑜已被去除。
C、InterSect形成交集
InterSect可以對兩個或多個結果集進行連接,形成“交集”。返回左邊結果集和右邊結果集中都有的記錄。
1、限定條件
要是用Except來連接結果集,有4個限定條件。
(1)、子結果集要具有相同的結構。
(2)、子結果集的列數必須相同。
(3)、子結果集對應的數據類型必須可以兼容。
(4)、每個子結果集不能包含order by或compute子句。
2、語法形式
select_statement intersect select_statement
示例:
SELECT Name FROM Person_1 INTERSECT SELECT Name FROM Person_2
返回的結果如下:
留意到只取兩張表都有的記錄(周瑜,孫權),這就是所謂的交集。
D、結果集的排序
SELECT Name FROM Person_1 INTERSECT SELECT Name FROM Person_2 ORDER BY Name DESC --此處的字段名相同了,如果不同,請切記排序列名,只能夠是第一個表的列名
這裏只有兩點要注意
1.ORDER BY是對整個運算後的結果排序,並不是對單個數據集。
2.ORDER BY後面排序的字段名稱是第一個數據集的字段名或者別名。