三个运算符

T-SQL支持三个集合运算符:UNION、INTERSECT、EXCEPT。

集合运算符查询的一般形式如下:

Query1
<set_operator>
Query2
-- 这里,ORDER BY子句对最终结果集进行排序
[ORDER BY...]

ORDER BY

在逻辑查询处理方面,集合运算符应用于两个查询结果集,且外部的ORDER BY子句(如果有的话)应用于集合运算所得到的结果集

每个独立的查询可以使用除了ORDER BY之外的所有逻辑查询处理阶段,原因如下:

  1. ORDER BY会对查询结果集进行排序

  2. 排序后的结果集不在表示一个集合而是游标

  3. 集合运算符只能用于集合间运算

因此,每个独立的查询语句中不能使用ORDER BY子句

其它查询逻辑

对集合运算结果集使用除ORDER BY之外的查询逻辑则易引发逻辑错误:

USE WJChi;

SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION ALL
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
WHERE Age>26;

-- 上述写法等价于(注意WHERE条件)
SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION ALL
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
WHERE U2.Age>26;

可以借助表表达式对集合运算符运算结果集使用ORDER BY之外的查询逻辑:

USE WJChi;

SELECT * FROM
(
SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION ALL
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
) AS T
WHERE T.Age>26;

上述查询也可使用派生表之外的表表达式,如:CTE。

集合的列

用于集合运算符的两个查询必须返回相同列数且对应列数据类型相互兼容的结果集。在进行比较运算时,集合运算符会认为两个NULL值是相等的

集合运算符返回结果集中的列名是第一个查询中的列名:

USE WJChi;

SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
ORDER BY Age

返回结果如下:

UNION

UNION用于获取两个集合的并集。

UNION运算符有两种形式:UNIONUNION ALL

UNION

USE WJChi;

SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
ORDER BY Age

返回结果如下:

UNION ALL

USE WJChi;

SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
UNION ALL
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
ORDER BY Age

返回结果如下:

从上面两个结果集中可以看到,UNIONUNION ALL的区别是:UNION会去除结果集中的重复元素,而UNION ALL不会,从性能上来讲,UNION ALL优于UNION。严格来讲,UNION ALL运算结果集不能称为集合,因为集合不存在重复元素。

INTERSECT

INTERSECT用于获取两个集合的交集,分为:INTERSECTINTERSECT ALL两种形式,二者区别同UNION运算符。

INTERSECT

可以使用内联接或者EXSITS谓词来替代INTERSECT,但在比较运算时,INTERSECT将两个NULL值视为相等,而替代方案不会。

INTERSECT只关注行的内容是否相同,不关注行出现的次数:

USE WJChi;

SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
INTERSECT
SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
ORDER BY Age;

INTERSECT ALL

SQL标准中包含INTERSECT ALL,但在SQL Server2014中未实现该特性,在SQL Server2014中使用INTERSECT ALL会报错:

不支持 INTERSECT 运算符的 'ALL' 版本。

UNION ALLALL的含义是返回所有重复行。与之类似,INTERSECT ALLALL的含义是不删除交集中的重复项。换个角度看,INTERSECT ALL不仅关心两侧存在的行,还关心每一侧行出现的次数,即:

如果某一数据在第一个输入中出现了a次,在第二个输入中出现了b次,那么在运算结果中该行出现min(a,b)次

下面,我们借助开窗函数ROW_NUMBER()实现了INTERSECT ALL的效果:

USE WJChi;

SELECT
ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
Name,Age
FROM dbo.UserInfo;

经过开窗函数ROW_NUMBER()的处理后,原本相同的数据被视为不同。

USE WJChi;

-- 实现INTERSECT ALL效果
SELECT T.Name,T.Age FROM
(
SELECT
ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
Name,Age
FROM dbo.UserInfo INTERSECT SELECT
ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
Name,Age
FROM dbo.UserInfo
) AS T
ORDER BY T.Age;

查询结果如下:

EXCEPT

EXCEPT用于获取两个集合的差集,与UNIONINTERSECT类似,EXCEPT也分为两种形式:EXCEPTEXCEPT ALL。同样,SQL Server2014也不支持EXCEPT ALL特性。

Query1
EXCEPT
Query2

EXCEPT

UNIONINTERSECT不同,EXCEPT运算符对于两个查询的先后顺序有要求:EXCEPT返回存在于Query1中出现且不在Query2中出现的行,EXCEPT只关注行是否重复,而不关注行出现的次数。

可以使用外联接或者NOT EXISTS来替代EXCEPT,但在比较运算时,EXCEPT将两个NULL值视为相等,而替代方案不会。

准备如下数据:

USE WJChi;

SELECT Name,Age FROM #temp;
SELECT Name,Age FROM dbo.UserInfo;

那么,下面两条SQL的运算结果集均不包含任何数据:

SELECT Name ,Age FROM #temp
EXCEPT
SELECT Name,Age FROM dbo.UserInfo
ORDER BY Age;

SELECT Name ,Age FROM dbo.UserInfo
EXCEPT
SELECT Name,Age FROM #temp
ORDER BY Age;

EXCEPT ALL

EXCEPT ALLEXCEPT的差异在于,EXCEPT ALL不止考虑行是否重复,还会考虑行出现的次数:

如果某一数据在第一个输入中出现了a次,在第二个输入中出现了b次,那么在运算结果中该行出现a-b次。若a<b则运算结果中不包含该行。

同样,我们借助开窗函数ROW_NUMBER()来实现EXCEPT ALL效果:

USE WJChi;

SELECT
T.Name,T.Age
FROM
(
SELECT
ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
Name,Age
FROM #temp EXCEPT SELECT
ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
Name,Age
FROM dbo.UserInfo
) AS T
ORDER BY T.Age;

小结

标准SQL支持三个集合运算符:UNIONINTERSECTEXCEPT,每个运算符均支持两种行为:去重(不带ALL关键字)和保留重复项(带上ALL关键字)。

T-SQL未提供对INTERSECT ALLEXCEPT ALL的支持,我们可以通过开窗函数ROW_NUMBER()来实现。

另外需要注意一点,集合运算符认为两个NULL是相等的。

推荐阅读

T-SQL基础(三)之子查询与表表达式

T-SQL基础(四)之集合运算的更多相关文章

  1. SQL基础学习_06_集合运算和联结

    集合运算 1. 并集:UNION     例:     SELECT shohin_id, shohin_mei    FROM Shohin    UNION    SELECT shohin_id ...

  2. SQL基础--查询之四--集合查询

    SQL基础--查询之四--集合查询

  3. SQL Server中的集合运算: UNION, EXCEPT和INTERSECT

    SQL Server中的集合运算包括UNION(合并),EXCEPT(差集)和INTERSECT(相交)三种. 集合运算的基本使用 1.UNION(合并两个查询结果集,隐式DINSTINCT,删除重复 ...

  4. SQL基础四(例子)

    ------------------------------------------------ --分别创建student/course/score表 Create table student ( ...

  5. 详解SQL集合运算

    以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列[T-SQL基础]主要是针对T-SQL基础的总结. [T-SQL基础]01.单表查询-几道sql查询题 ...

  6. SQL Server温故系列(4):SQL 查询之集合运算 & 聚合函数

    1.集合运算 1.1.并集运算 UNION 1.2.差集运算 EXCEPT 1.3.交集运算 INTERSECT 1.4.集合运算小结 2.聚合函数 2.1.求行数函数 COUNT 2.2.求和函数 ...

  7. 集合运算 & 聚合函数

    SQL 查询之集合运算 & 聚合函数   1.集合运算 1.1.并集运算 UNION 1.2.差集运算 EXCEPT 1.3.交集运算 INTERSECT 1.4.集合运算小结 2.聚合函数 ...

  8. [SQL] SQL 基础知识梳理(七)- 集合运算

    SQL 基础知识梳理(七)- 集合运算 目录 表的加减法 联结(以列为单位) 一.表的加减法 1.集合:记录的集合(表.视图和查询的执行结果). 2.UNION(并集):表的加法 -- DDL:创建表 ...

  9. SQL基础教程(第2版)第7章 集合运算:7-2 联结(以列为单位对表进行联结)

    第7章 集合运算:7-2 联结(以列为单位对表进行联结) ■联结的特定语法和过时语法 ● 联结( JOIN)就是将其他表中的列添加过来,进行“添加列”的集合运算.UNION是以行(纵向)为单位进行操作 ...

随机推荐

  1. 9-Unittest+HTMLTestRunner不能生成报告解决方法

    1.问题现象 在使用HTMLTestRunner生成测试报告时,出现程序运行不报错,但不能生成报告的情况. 刚开始找了很久没发现问题,后来加上打印信息,发现根本没执行生成报告这部分代码.最后网上找到原 ...

  2. React了解

    根据博主  http://www.ruanyifeng.com/blog/2015/03/react.html  的几个Demo(https://github.com/ruanyf/react-dem ...

  3. django2+python3+uwsgi+centos7部署网站

    Centos7中安装Python虚拟环境 2018年08月27日 00:09:36 kaichenkai 阅读数:984 1.为什么要搭建虚拟环境? 问题:如果在一台电脑上, 想开发多个不同的项目, ...

  4. 一个xss漏洞到内网漫游【送多年心血打造的大礼包啦!】

    i春秋作家:jasonx 原文来自:一个xss漏洞到内网漫游[送多年心血打造的大礼包啦!] 前言 渗透过程中,有时候遇某些网站,明明检测到有xss漏洞,但是盲打以后,收到的cookie还是不能登录后台 ...

  5. Java 虚拟机的内存溢出

    在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能. 在Eclipse中进行JVM参数设置 可以直接通过上方菜单栏的 ...

  6. cryptoJS AES 加解密简单使用

    简单记录一下,前端利用 cryptoJS 如何加解密的.主要是关于 AES 加解密. 需求描述:需要对 url 中的参数进行 AES 解密,然后再把该参数进行 MD5 加密通过接口传递. AES AE ...

  7. Canny算子

    Canny边缘检测算子是John F. Canny于1986年开发出来的一个多级边缘检测算法.更为重要的是Canny创立了“边缘检测计算理论”(computational theory of edge ...

  8. centos7进入单用户模式

    当我们设置用户密码时,有可能会忘记,这时如何登陆呢,单用户模式就可以 首先我们进入开机界面,按e进行选择 会进入以下界面, 然后找到图中红线标注的该行,在行尾添加 init=/bin/sh 按住Ctr ...

  9. 激活IDEA方法

    1.需要一个jar包,在 http://idea.lanyus.com/  下载 2.将jar拷贝到idea安装目录 3.复制jar包路径   到如下图两个文件中 例:-javaagent:C:\Ap ...

  10. linux 清空历史命令

    系统版本:CentOS 6 history -c 命令可以清空当前窗口的历史输出命令. 要彻底删除历史命令可以有如下几种方式: 在当前用户的-目录下执行: 方式1: echo > .bash_h ...