集运算符 - UNION (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric 中的 SQL 分析终结点Microsoft Fabric 中的仓库

将两个查询的结果连接到一个结果集中。 可控制结果集是否包含重复行:

  • UNION ALL - 包括重复行。
  • UNION - 排除重复行。

UNION 操作不同于 JOIN 操作 :

  • UNION 连接两个查询中的结果集。 但 UNION 不会从两个表收集的列中创建单独的行。
  • JOIN 比较两个表中的列,以创建由两个表中的列组成的结果行。

下面列出了使用 UNION 合并两个查询结果集的基本规则:

  • 所有查询中的列数和列的顺序必须相同。

  • 数据类型必须兼容。

Transact-SQL 语法约定

语法

{ <query_specification> | ( <query_expression> ) }   
{ UNION [ ALL ]   
  { <query_specification> | ( <query_expression> ) } 
  [ ...n ] }

注意

若要查看 SQL Server 2014 (12.x) 及更早版本的 Transact-SQL 语法,请参阅早期版本文档

参数

<query_specification> | ( <query_expression> ) 是一个查询规范或查询表达式,用以返回要与另一个查询规范或查询表达式所返回的数据合并的数据。 属于 UNION 运算的列定义不一定要相同,但必须可通过隐式转换实现兼容。 如果数据类型不同,则根据数据类型优先级规则确定所产生的数据类型。 如果类型相同,但精度、确定位数或长度不同,那么结果以相同的表达式合并规则为依据。 有关详细信息,请参阅精度、小数位数和长度 (Transact-SQL)

xml 数据类型的列必须相等。 所有的列必须类型化为 XML 架构或是非类型化的。 如果要类型化,这些列必须类型化为相同的 XML 架构集合。

UNION
指定合并多个结果集并将其作为单个结果集返回。

ALL
将全部行都纳入结果,包括重复行。 如果未指定该参数,则删除重复行。

示例

A. 使用简单 UNION

在下面的示例中,结果集同时包含 ProductModelIDName 表中的 ProductModelGloves 列中的内容。

-- Uses AdventureWorks  
  
IF OBJECT_ID ('dbo.Gloves', 'U') IS NOT NULL  
DROP TABLE dbo.Gloves;  
GO  
-- Create Gloves table.  
SELECT ProductModelID, Name  
INTO dbo.Gloves  
FROM Production.ProductModel  
WHERE ProductModelID IN (3, 4);  
GO  
  
-- Here is the simple union.  
-- Uses AdventureWorks  
  
SELECT ProductModelID, Name  
FROM Production.ProductModel  
WHERE ProductModelID NOT IN (3, 4)  
UNION  
SELECT ProductModelID, Name  
FROM dbo.Gloves  
ORDER BY Name;  
GO  

B. 将 SELECT INTO 与 UNION 一起使用

在下面的示例中,第二个 SELECT 语句中的 INTO 子句指定,ProductResults 表保留 ProductModelGloves 表中选定列的并集的最终结果集。 Gloves 表是在第一个 SELECT 语句中创建。

-- Uses AdventureWorks  
  
IF OBJECT_ID ('dbo.ProductResults', 'U') IS NOT NULL  
DROP TABLE dbo.ProductResults;  
GO  
IF OBJECT_ID ('dbo.Gloves', 'U') IS NOT NULL  
DROP TABLE dbo.Gloves;  
GO  
-- Create Gloves table.  
SELECT ProductModelID, Name  
INTO dbo.Gloves  
FROM Production.ProductModel  
WHERE ProductModelID IN (3, 4);  
GO  
  
-- Uses AdventureWorks  
  
SELECT ProductModelID, Name  
INTO dbo.ProductResults  
FROM Production.ProductModel  
WHERE ProductModelID NOT IN (3, 4)  
UNION  
SELECT ProductModelID, Name  
FROM dbo.Gloves;  
GO  
  
SELECT ProductModelID, Name   
FROM dbo.ProductResults;  

C. 将 ORDER BY 与两个 SELECT 语句的 UNION 一起使用

在 UNION 子句中使用的某些参数的顺序非常重要。 下面的示例通过两个 UNION 语句说明 SELECT 的错误用法和正确用法(在这两个语句的输出中将重命名一个列)。

-- Uses AdventureWorks  
  
IF OBJECT_ID ('dbo.Gloves', 'U') IS NOT NULL  
DROP TABLE dbo.Gloves;  
GO  
-- Create Gloves table.  
SELECT ProductModelID, Name  
INTO dbo.Gloves  
FROM Production.ProductModel  
WHERE ProductModelID IN (3, 4);  
GO  
  
/* INCORRECT */  
-- Uses AdventureWorks  
  
SELECT ProductModelID, Name  
FROM Production.ProductModel  
WHERE ProductModelID NOT IN (3, 4)  
ORDER BY Name  
UNION  
SELECT ProductModelID, Name  
FROM dbo.Gloves;  
GO  
  
/* CORRECT */  
-- Uses AdventureWorks  
  
SELECT ProductModelID, Name  
FROM Production.ProductModel  
WHERE ProductModelID NOT IN (3, 4)  
UNION  
SELECT ProductModelID, Name  
FROM dbo.Gloves  
ORDER BY Name;  
GO  

D. 使用三个 SELECT 语句的 UNION 来说明 ALL 和括号的作用

下列示例使用 UNION 来组合具有相同 5 行数据的三个表的结果。 第一个示例使用 UNION ALL 显示重复记录,返回所有的 15 行。 第二个示例使用不带 UNIONALL,删除三个 SELECT 语句的组合结果中的重复行,返回 5 行。

第三个示例将 ALL 用于第一个 UNION,并用括号将没有使用 ALL 的第二个 UNION 括起来。 第二个 UNION 因位于括号内而首先得到处理,并返回 5 行,这是因为未使用 ALL 选项,重复行遭删除。 通过使用 SELECT 关键字将这 5 行与第一个 UNION ALL 的结果组合在一起。 下面的示例不删除两个 5 行结果集之间的重复行。 最终结果有 10 行。

-- Uses AdventureWorks  
  
IF OBJECT_ID ('dbo.EmployeeOne', 'U') IS NOT NULL  
DROP TABLE dbo.EmployeeOne;  
GO  
IF OBJECT_ID ('dbo.EmployeeTwo', 'U') IS NOT NULL  
DROP TABLE dbo.EmployeeTwo;  
GO  
IF OBJECT_ID ('dbo.EmployeeThree', 'U') IS NOT NULL  
DROP TABLE dbo.EmployeeThree;  
GO  
  
SELECT pp.LastName, pp.FirstName, e.JobTitle   
INTO dbo.EmployeeOne  
FROM Person.Person AS pp JOIN HumanResources.Employee AS e  
ON e.BusinessEntityID = pp.BusinessEntityID  
WHERE LastName = 'Johnson';  
GO  
SELECT pp.LastName, pp.FirstName, e.JobTitle   
INTO dbo.EmployeeTwo  
FROM Person.Person AS pp JOIN HumanResources.Employee AS e  
ON e.BusinessEntityID = pp.BusinessEntityID  
WHERE LastName = 'Johnson';  
GO  
SELECT pp.LastName, pp.FirstName, e.JobTitle   
INTO dbo.EmployeeThree  
FROM Person.Person AS pp JOIN HumanResources.Employee AS e  
ON e.BusinessEntityID = pp.BusinessEntityID  
WHERE LastName = 'Johnson';  
GO  
-- Union ALL  
SELECT LastName, FirstName, JobTitle  
FROM dbo.EmployeeOne  
UNION ALL  
SELECT LastName, FirstName ,JobTitle  
FROM dbo.EmployeeTwo  
UNION ALL  
SELECT LastName, FirstName,JobTitle   
FROM dbo.EmployeeThree;  
GO  
  
SELECT LastName, FirstName,JobTitle  
FROM dbo.EmployeeOne  
UNION   
SELECT LastName, FirstName, JobTitle   
FROM dbo.EmployeeTwo  
UNION   
SELECT LastName, FirstName, JobTitle   
FROM dbo.EmployeeThree;  
GO  
  
SELECT LastName, FirstName,JobTitle   
FROM dbo.EmployeeOne  
UNION ALL  
(  
SELECT LastName, FirstName, JobTitle   
FROM dbo.EmployeeTwo  
UNION  
SELECT LastName, FirstName, JobTitle   
FROM dbo.EmployeeThree  
);  
GO  
  

示例:Azure Synapse Analytics 和 Analytics Platform System (PDW)

E. 使用简单 UNION

在下面的示例中,结果集同时包含 FactInternetSalesDimCustomer 表中的 CustomerKey 列中的内容。 由于未使用 ALL 关键字,因此重复行会从结果中排除。

-- Uses AdventureWorks  
  
SELECT CustomerKey   
FROM FactInternetSales    
UNION   
SELECT CustomerKey   
FROM DimCustomer   
ORDER BY CustomerKey;  

F. 将 ORDER BY 与两个 SELECT 语句的 UNION 一起使用

当 UNION 语句中的任何 SELECT 语句包含 ORDER BY 子句时,该子句应置于所有 SELECT 语句之后。 下面的示例通过两个 SELECT 语句说明 UNION 的错误用法和正确用法(在这两个语句中使用 ORDER BY 对一个列排序)。

-- Uses AdventureWorks  
  
-- INCORRECT  
SELECT CustomerKey   
FROM FactInternetSales    
ORDER BY CustomerKey  
UNION   
SELECT CustomerKey   
FROM DimCustomer  
ORDER BY CustomerKey;  
  
-- CORRECT   
USE AdventureWorksPDW2012;  
  
SELECT CustomerKey   
FROM FactInternetSales    
UNION   
SELECT CustomerKey   
FROM DimCustomer   
ORDER BY CustomerKey;  

G. 将 WHERE 和 ORDER BY 与两个 SELECT 语句的 UNION 一起使用

下面的示例通过两个 SELECT 语句说明 UNION 的错误用法和正确用法(在这两个语句中需要 WHERE 和 ORDER BY)。

-- Uses AdventureWorks  
  
-- INCORRECT   
SELECT CustomerKey   
FROM FactInternetSales   
WHERE CustomerKey >= 11000  
ORDER BY CustomerKey   
UNION   
SELECT CustomerKey   
FROM DimCustomer   
ORDER BY CustomerKey;  
  
-- CORRECT  
USE AdventureWorksPDW2012;  
  
SELECT CustomerKey   
FROM FactInternetSales   
WHERE CustomerKey >= 11000  
UNION   
SELECT CustomerKey   
FROM DimCustomer   
ORDER BY CustomerKey;  

H. 使用三个 SELECT 语句的 UNION 来说明 ALL 和括号的作用

下面的示例使用 UNION 合并同一个表的结果,以展示使用 UNION 时 ALL 和括号的效果。

第一个示例使用 UNION ALL 显示重复记录,并三次返回源表中的每一行。 第二个示例使用不带 ALLUNION,删除三个 SELECT 语句的组合结果中的重复行,仅返回源表中的非重复行。

第三个示例将 ALL 用于第一个 UNION,并用括号将没有使用 ALL 的第二个 UNION 括起来。 首先处理第二个 UNION,因为它位于括号中。 仅从表返回非重复行,因为未使用 ALL 选项,重复行遭删除。 通过使用 UNION ALL 关键字将这些行与第一个 SELECT 的结果合并在一起。 下面的示例不删除两个结果集之间的重复行。

-- Uses AdventureWorks  
  
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION ALL   
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION ALL   
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer;  
  
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION   
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION   
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer;  
  
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION ALL  
(  
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
UNION   
SELECT CustomerKey, FirstName, LastName  
FROM DimCustomer  
);  

另请参阅

SELECT (Transact-SQL)
SELECT 示例 (Transact-SQL)