如何利用 SQL UNION 操作符將多條 SELECT 語句組合成一個結果集
本文介紹如何利用 SQL UNION
操作符將多條 SELECT 語句組合成一個結果集。使用 UNION
可極大地簡化複雜的 WHERE
子句,簡化從多個表中檢索資料的工作。
一、組合查詢
多數 SQL 查詢只包含從一個或多個表中返回資料的單條 SELECT
語句。但是,SQL 也允許執行多個查詢(多條 SELECT
語句),並將結果作為一個查詢結果集返回。
這些組合查詢通常稱為並(union)或複合查詢(compound query)。
主要有兩種情況需要使用組合查詢:
- 在一個查詢中從不同的表返回結構資料;
- 對一個表執行多個查詢,按一個查詢返回資料。
提示:組合查詢和多個
WHERE
條件多數情況下,組合相同表的兩個查詢所完成的工作與具有多個
WHERE
子句條件的一個查詢所完成的工作相同。換句話說,任何具有多個
WHERE
子句的SELECT
語句都可以作為一個組合查詢,在下面可以看到這一點。
二、建立組合查詢
可用 UNION
操作符來組合數條 SQL 查詢。利用 UNION
,可給出多條 SELECT
語句,將它們的結果組合成一個結果集。
2.1 使用 UNION
使用 UNION
很簡單,所要做的只是給出每條 SELECT
UNION
。
舉個例子,假如需要 Illinois
、Indiana
和 Michigan
等美國幾個州的所有顧客的報表,還想包括不管位於哪個州的所有的 Fun4All
。
當然可以利用 WHERE
子句來完成此工作,不過這次我們使用 UNION
。
如上所述,建立 UNION
涉及編寫多條 SELECT
語句。首先來看單條語句:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI');
輸出:
cust_name cust_contact cust_email ----------- ------------- ------------ Village Toys John Smith [email protected] Fun4All Jim Jones [email protected] The Toy Store Kim Howard NULL
輸入:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';
輸出:
cust_name cust_contact cust_email
----------- ------------- ------------
Fun4All Jim Jones [email protected]
Fun4All Denise L. Stephens [email protected]
第一條 SELECT
把 Illinois
、Indiana
、Michigan
等州的縮寫傳遞給 IN
子句,檢索出這些州的所有行。
第二條 SELECT
利用簡單的相等測試找出所有 Fun4All
。你會發現有一條記錄出現在兩次結果裡,因為它滿足兩次的條件。
組合這兩條語句,可以如下進行:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';
輸出:
cust_name cust_contact cust_email
----------- ----------- ----------------
Fun4All Denise L. Stephens [email protected]
Fun4All Jim Jones [email protected]
Village Toys John Smith [email protected]
The Toy Store Kim Howard NULL
這條語句由前面的兩條 SELECT
語句組成,之間用 UNION
關鍵字分隔。UNION
指示 DBMS 執行這兩條 SELECT
語句,並把輸出組合成一個查詢結果集。
為了便於參考,這裡給出使用多條 WHERE
子句而不是 UNION
的相同查詢:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI') OR cust_name='Fun4All';
在這個簡單的例子中,使用 UNION
可能比使用 WHERE
子句更為複雜。但對於較複雜的過濾條件,或者從多個表(而不是一個表)中檢索資料的情形,使用 UNION
可能會使處理更簡單。
提示:
UNION
的限制使用
UNION
組合SELECT
語句的數目,SQL 沒有標準限制。但是,最好是參考一下具體的 DBMS 文件,瞭解它是否對UNION
能組合的最大語句數目有限制。
注意:效能問題
多數好的 DBMS 使用內部查詢優化程式,在處理各條
SELECT
語句前組合它們。理論上講,這意味著從效能上看使用多條
WHERE
子句條件還是UNION
應該沒有實際的差別。不過我說的是理論上,實踐中多數查詢優化程式並不能達到理想狀態,所以最好測試一下這兩種方法,看哪種工作得更好。
2.2 UNION 規則
可以看到,UNION
非常容易使用,但在進行組合時需要注意幾條規則。
-
UNION
必須由兩條或兩條以上的SELECT
語句組成,語句之間用關鍵字UNION
分隔(因此,如果組合四條SELECT
語句,將要使用三個UNION
關鍵字)。 -
UNION
中的每個查詢必須包含相同的列、表示式或聚集函式(不過,各個列不需要以相同的次序列出)。 - 列資料型別必須相容:型別不必完全相同,但必須是 DBMS 可以隱含轉換的型別(例如,不同的數值型別或不同的日期型別)。
說明:
UNION
的列名如果結合
UNION
使用的SELECT
語句遇到不同的列名,那麼會返回什麼名字呢?比如說,如果一條語句是SELECT prod_name
,而另一條語句是SELECT productname
,那麼查詢結果返回的是什麼名字呢?答案是它會返回第一個名字,舉的這個例子就會返回
prod_name
,而不管第二個不同的名字。這也意味著你可以對第一個名字使用別名,因而返回一個你想要的名字。這種行為帶來一個有意思的副作用。由於只使用第一個名字,那麼想要排序也只能用這個名字。
拿我們的例子來說,可以用
ORDER BY prod_name
對結果排序,如果寫成ORDER BY productname
就會出錯,因為查詢結果裡沒有叫作productname
的列。
如果遵守了這些基本規則或限制,則可以將 UNION
用於任何資料檢索操作。
2.3 包含或取消重複的行
回到 2.1 節,我們看看所用的 SELECT
語句。
注意到在分別執行語句時,第一條 SELECT
語句返回 3 行,第二條 SELECT
語句返回 2 行。而在用 UNION
組合兩條 SELECT
語句後,只返回 4 行而不是 5 行。
UNION
從查詢結果集中自動去除了重複的行;換句話說,它的行為與一條 SELECT
語句中使用多個 WHERE
子句條件一樣。
因為 Indiana
州有一個 Fun4All
單位,所以兩條 SELECT
語句都返回該行。使用 UNION
時,重複的行會被自動取消。
這是 UNION
的預設行為,如果願意也可以改變它。事實上,如果想返回所有的匹配行,可使用 UNION ALL
而不是 UNION
。
請看下面的例子:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';
輸出:
cust_name cust_contact cust_email
----------- ------------- ------------
Village Toys John Smith [email protected]
Fun4All Jim Jones [email protected]
The Toy Store Kim Howard NULL
Fun4All Jim Jones [email protected]
Fun4All Denise L. Stephens [email protected]
使用 UNION ALL
,DBMS 不取消重複的行。因此,這裡返回 5 行,其中有一行出現兩次。
提示:
UNION
與WHERE
本文一開始我們說過,
UNION
幾乎總是完成與多個WHERE
條件相同的工作。
UNION ALL
為UNION
的一種形式,它完成WHERE
子句完成不了的工作。如果確實需要每個條件的匹配行全部出現(包括重複行),就必須使用
UNION ALL
,而不是WHERE
。
2.4 對組合查詢結果排序
SELECT
語句的輸出用 ORDER BY
子句排序。
在用 UNION
組合查詢時,只能使用一條 ORDER BY
子句,它必須位於最後一條 SELECT
語句之後。
對於結果集,不存在用一種方式排序一部分,而又用另一種方式排序另一部分的情況,因此不允許使用多條 ORDER BY
子句。
下面的例子對前面 UNION
返回的結果進行排序:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'
ORDER BY cust_name, cust_contact;
輸出:
cust_name cust_contact cust_email
----------- ------------- -------------
Fun4All Denise L. Stephens [email protected]
Fun4All Jim Jones [email protected]
The Toy Store Kim Howard NULL
Village Toys John Smith [email protected]
這條 UNION
在最後一條 SELECT
語句後使用了 ORDER BY
子句。
雖然 ORDER BY
子句似乎只是最後一條 SELECT
語句的組成部分,但實際上 DBMS 將用它來排序所有 SELECT
語句返回的所有結果。
說明:其他型別的
UNION
某些 DBMS 還支援另外兩種
UNION
:EXCEPT
(有時稱為MINUS
)可用來檢索只在第一個表中存在而在第二個表中不存在的行;而
INTERSECT
可用來檢索兩個表中都存在的行。實際上,這些UNION
很少使用,因為相同的結果可利用聯結得到。
提示:操作多個表
為了簡單,本文中的例子都是使用
UNION
來組合針對同一表的多個查詢。實際上,
UNION
在需要組合多個表的資料時也很有用,即使是有不匹配列名的表,在這種情況下,可以將UNION
與別名組合,檢索一個結果集。
三、小結
本文介紹瞭如何用 UNION
操作符來組合 SELECT
語句。利用 UNION
,可以把多條查詢的結果作為一條組合查詢返回,不管結果中有無重複。
使用 UNION
可極大地簡化複雜的 WHERE
子句,簡化從多個表中檢索資料的工作。
原文連結:https://www.developerastrid.com/sql/sql-union/
(完)