本文章为 SQL Server 的详细学习大纲 里面的一个子章节的详细介绍,如果想了解相关的其他内容,可以从这里面查看,或者查看SQL Server专栏,里面有些文章可能并不在 SQL Server 的详细学习大纲 里面,以及一些补充内容。
一、简单介绍
- 有时候希望对查询的多个结果集做合并、交集、差集运算。SQL Server 提供了多个集运算符来给我们进行运算,以下是对各个集运算符做一些简单的介绍。
- UNION 合并两个或多个 SELECT 语句的结果集,去掉重复的行。
- UNION ALL 合并两个或多个 SELECT 语句的结果集,不去掉重复的行。
- INTERSECT 返回两个或多个 SELECT 语句结果集的交集。
- EXCEPT 返回在第一个 SELECT 语句结果集中存在,但在第二个 SELECT 语句结果集中不存在的行。
- 注意点
- 多个 SELECT 语句的结果集的列定义不一定要相同,但必须可通过隐式转换实现兼容。 如果数据类型不同,则根据数据类型优先级规则确定所产生的数据类型。 如果类型相同,但精度、确定位数或长度不同,那么结果以相同的表达式合并规则为依据。
- 返回的列名显示的是第一个结果集的列名称,如果后面要使用ORDER BY ,要使用第一个结果集的列名,否则会报错
二、构建测试数据
-- 创建表TableA
CREATE TABLE TableA (
ID INT,
AName VARCHAR(50)
);
-- 创建表TableB
CREATE TABLE TableB (
ID INT,
BName VARCHAR(50)
);
-- 向TableA插入数据
INSERT INTO TableA (ID, AName) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie');
-- 向TableB插入数据
INSERT INTO TableB (ID, BName) VALUES
(2, 'Bob'),
(3, 'Charlie'),
(4, 'David');
select * from TableA;
select * from TableB;
结果:
三、UNION与UNION ALL
- 两个结果集代码演示
-- 使用UNION合并TableA和TableB的数据,去除重复行,列名显示第一个结果集
SELECT ID, AName FROM TableA
UNION
SELECT ID, BName FROM TableB
;
-- 使用UNION ALL合并TableA和TableB的数据,不去除重复行,列名显示第一个结果集
SELECT ID, AName FROM TableA
UNION ALL
SELECT ID, BName FROM TableB
;
-
结果:
返回的列名显示的是第一个结果集的列名称 -
多个结果集演示
SELECT ID, AName FROM TableA
UNION ALL
SELECT ID, BName FROM TableB
UNION ALL
SELECT ID, BName FROM TableB
……
四、INTERSECT与EXCEPT
- 代码演示
-- 交集,TableA与TableB均有的数据,列名显示第一个结果集
SELECT ID, AName FROM TableA
INTERSECT
SELECT ID, BName FROM TableB
;
-- 差集,TableA去掉在TableB存在的数据行
SELECT ID, AName FROM TableA
EXCEPT
SELECT ID, BName FROM TableB
;
- 结果
五、ORDER BY 与集合操作符
- 几个常见的错误
- 位置问题,不在操作结果集的最后面
- 在结果集的最后面,但用的列不是第一个结果集的列
示例一:
SELECT ID, AName FROM TableA
ORDER BY AName
UNION
SELECT ID, BName FROM TableB
结果:
示例二:
SELECT ID, AName FROM TableA
UNION
SELECT ID, BName FROM TableB
ORDER BY BName
;
结果:
原因是因为ORDER BY 只能操作集运算之后的结果,不能进行操作子集,即使你把子集合用()包起来
示例三:
SELECT ID, AName FROM TableA
UNION ALL
select * from(
SELECT ID, BName FROM TableB
ORDER BY BName) B
;
结果:
六、WHERE与集合操作符使用
WHERE与ORDER BY 不一样,这个是对子集合进行操作的,不是对结果进行操作的,以下是两个语句的示例:
-- 对的,WHERE语句是对子集TableB的操作,过滤之后再进行合并操作
SELECT ID, AName FROM TableA
UNION
SELECT ID, BName FROM TableB
WHERE BName ='Bob'
;
-- 错的,WHERE语句是对子集TableB的操作,TableB没有列名为AName的列,会报错
SELECT ID, AName FROM TableA
UNION
SELECT ID, BName FROM TableB
WHERE AName ='Bob'
;
- 对结果集运算的结果进行过滤可以使用子查询,如:
SELECT * FROM (
SELECT ID, AName FROM TableA
UNION
SELECT ID, BName FROM TableB
) A
WHERE AName ='Bob'
;
结果:
七、SELECT INTO 与集运算符使用
SELECT INTO 与ORDER BY 一样,都是对结果集进行操作的,也就是合并、交集、差集之后的结果,再进行INTO操作。
SELECT ID, AName INTO TEST FROM TableA
EXCEPT
SELECT ID, BName FROM TableB
;
SELECT * FROM TEST
结果:
八、结尾
这几个集运算符除了运算的逻辑不一样外,其他的操作逻辑都是一样的,所以这里合并在一起进行说明,例子也只进行对一个集运算符进行说明,其实其他的几个也是一样的。原理都是一样的,我们要学会扩展思维,也可以自己多进行验证,只要弄懂了一个,其他的基本也懂了。