問題
有時需要將來自多個表或視圖的數據合並到一個綜合的數據集中。這可能是針對同一數據庫中具有相似數據的表,或者可能需要跨數據庫甚至跨服務器組合相似數據。
在本文中,我們將介紹如何使用UNION與UNION ALL命令以及它們之間的區別。
解
在SQL Server中,您可以使用UNION或UNION ALL運算符將多個數據集組合為一個綜合數據集。它們的工作方式以及返回的最終結果集有很大的不同,但是基本上,這些命令將具有相似結構的多個數據集合並到一個組合的數據集中。
UNION
此操作將使您可以將多個數據集合並為一個數據集,並刪除所有存在的重復項。基本上,它在結果集中的所有列上執行DISTINCT操作。
UNION ALL
再次執行此操作,您可以將多個數據集連接到一個數據集中,但是不會刪除任何重復的行。因為這不會刪除重復的行,所以此過程更快,但是如果您不希望重復的記錄,則需要使用UNION運算符。
UNION數據規則
- 每個查詢的列數必須相同
- 每列必須具有兼容的數據類型
- 最終結果集的列名取自第一個查詢
- ORDER BY和COMPUTE子句只能針對整個結果集發出,而不能在每個單獨的結果集中發出
- GROUP BY和HAVING子句只能為每個單獨的結果集發出,而不能為整體結果集發出
提示:如果所有查詢中的列都不完全相同,請使用默認值或NULL值,例如:
SELECT firstName, lastName, company FROM businessContacts
UNION
SELECT firstName, lastName, NULL FROM nonBusinessContacts
or
SELECT firstName, lastName, createDate FROM businessContacts
UNION ALL
SELECT firstName, lastName, getdate() FROM nonBusinessContacts
UNION vs. UNION ALL示例
讓我們看一下這些命令如何工作以及它們如何不同的一些簡單示例。正如您將看到的,最終結果集將有所不同,但是有關SQL Server如何實際完成該過程的信息有些有趣。
UNION ALL
在第一個示例中,我們對AdventureWorks數據庫中的Employee表使用UNION ALL運算符。這可能不是您要執行的操作,但這有助於說明這兩個運算符的區別。
表dbo.Employee中有290行。
SELECT * FROM HumanResources.Employee UNION ALL SELECT * FROM HumanResources.Employee UNION ALL SELECT * FROM HumanResources.Employee
運行此查詢時,結果集將包含870行。這是290行返回了3次。只是將一個數據集放到另一個數據集之上。
這是此查詢的執行計划。我們可以看到該表被查詢了3次,並且SQL Server執行了“連接”步驟來連接所有數據。
UNION
在下一個示例中,我們再次從AdventureWorks數據庫中對Employee表使用UNION運算符。
SELECT * FROM HumanResources.Employee UNION SELECT * FROM HumanResources.Employee UNION SELECT * FROM HumanResources.Employee
運行此查詢時,結果集有290行。即使我們將數據合並了三遍,UNION運算符也刪除了重復的記錄,因此僅返回了290個唯一行。
這是此查詢的執行計划。我們可以看到SQL Server首先查詢了兩個表,然后執行了合並聯接操作以合並前兩個表,然后又執行了另一個合並聯接並查詢了查詢中的第三個表。因此,我們可以看到,與UNION ALL相比,要獲得此結果集還需要執行更多的工作。
在聚集索引列上排序的UNION vs.UNION ALL示例
如果我們更進一步,並使用“聚簇索引”列對數據進行SORT,我們將獲得這些執行計划。從中我們可以看到,盡管最終結果集仍然包含UNION ALL的870行和UNION ALL的290行,但SQL Server使用的執行計划對於這些操作中的每一個都是相同的。
在聚集索引列上排序的UNION ALL執行計划
對聚集索引列進行排序的UNION執行計划
在非索引列上排序的UNION vs.UNION ALL示例
這是另一個做同樣事情的例子,但是這次是對非索引列進行SORT。如您所見,這兩個查詢的執行計划再次相同,但是這次不是使用MERGE JOIN,而是使用了CONCATENATION和SORT操作。
UNION ALL執行計划,排序時帶有非索引列
具有非索引列排序的UNION執行計划
