三个运算符

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

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

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

ORDER BY

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

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

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

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

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

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

其它查询逻辑

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

  1. USE WJChi;

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

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

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

  1. USE WJChi;

  2. SELECT * FROM
  3. (
  4. SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
  5. UNION ALL
  6. SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
  7. ) AS T
  8. WHERE T.Age>26;

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

集合的列

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

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

  1. USE WJChi;

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

返回结果如下:

UNION

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

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

UNION

  1. USE WJChi;

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

返回结果如下:

UNION ALL

  1. USE WJChi;

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

返回结果如下:

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

INTERSECT

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

INTERSECT

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

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

  1. USE WJChi;

  2. SELECT Name AS 姓名,Age FROM dbo.UserInfo AS U1
  3. INTERSECT
  4. SELECT Name,Age AS 年龄 FROM dbo.UserInfo AS U2
  5. 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的效果:

  1. USE WJChi;

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

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

  1. USE WJChi;

  2. -- 实现INTERSECT ALL效果
  3. SELECT T.Name,T.Age FROM
  4. (
  5. SELECT
  6. ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
  7. Name,Age
  8. FROM dbo.UserInfo
  9.  
  10. INTERSECT
  11.  
  12. SELECT
  13. ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
  14. Name,Age
  15. FROM dbo.UserInfo
  16. ) AS T
  17. ORDER BY T.Age;

查询结果如下:

EXCEPT

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

  1. Query1
  2. EXCEPT
  3. Query2

EXCEPT

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

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

准备如下数据:

  1. USE WJChi;

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

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

  1. SELECT Name ,Age FROM #temp
  2. EXCEPT
  3. SELECT Name,Age FROM dbo.UserInfo
  4. ORDER BY Age;

  5. SELECT Name ,Age FROM dbo.UserInfo
  6. EXCEPT
  7. SELECT Name,Age FROM #temp
  8. ORDER BY Age;

EXCEPT ALL

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

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

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

  1. USE WJChi;

  2. SELECT
  3. T.Name,T.Age
  4. FROM
  5. (
  6. SELECT
  7. ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
  8. Name,Age
  9. FROM #temp
  10.  
  11. EXCEPT
  12.  
  13. SELECT
  14. ROW_NUMBER() OVER(PARTITION BY Name,Age ORDER BY Age) AS RowNumber,
  15. Name,Age
  16. FROM dbo.UserInfo
  17. ) AS T
  18. 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. CSS中的px与物理像素、逻辑像素、1px边框问题

    一直不太清楚CSS中的1px与逻辑像素.物理像素是个什么关系(作为一名前端感觉很惭愧 -_-!),今天终于花时间彻底弄清楚了,其实弄清楚之后就觉得事情很简单,但也只有在弄清楚之后,才会觉得简单(语出& ...

  2. Nerd的套现ATM机

    Nerd是一群似乎只在学生阶段才出尽风头的人.不善言辞,闷头学习,每遇考试便战功赫赫风光无限,赢得天下名.这样的描述,对那些成绩一般.喜欢天马行空.甚至有些多动症倾向的人来讲,无异于是噩梦.幸好有社会 ...

  3. Spark从入门到精通(一)

    什么是Spark 大数据计算框架 离线批处理 大数据体系架构图(Spark) Spark包含了大数据领域常见的各种计算框架:比如Spark Core用于离线计算,Spark SQL用于交互式查询,Sp ...

  4. 【MySQL】sql_mode引起的一个问题和总结

    [背景] 之前项目中,项目组计划将现场的MySQL5.5升级到5.7,以提升主从同步性能.使用半同步复制,以及解决一些现场问题等.安排测试组进行验证,测试同事反馈实验室环境中发现有入库失败,我查看了e ...

  5. python中的进制转换

    python中常用的进制转化通常有两种方法: 1.用内置函数hex(),oct(),bin(),对应的数字表示为0x,0o,0b,功能是把十进制数字转化为其他进制  >>> int( ...

  6. LeetCode20:validParentheses

    validParentheses 题目描述 Given a string containing just the characters '(', ')', '{', '}', '[' and ']', ...

  7. jsbridge的js封装

    /*注意:源生app需要配置jsbridge的环境,而在前端页面中需要下方封装代码,既可以达到调用app方法的功能和注册供app调用的方法1.注册方法:注册后,供app调用,注册时,同名函数,下一个会 ...

  8. java中的正则表达式捕获组与引用的概念

    今天群里有个人问,怎样用增则表达式匹配三角形的三边,其实只是要匹配三个数字而已,如 301 402 503 开始认为很简单,我就写了一个   "(([1-9]\\d?)\\s){2}$2&q ...

  9. 课程五(Sequence Models),第三周(Sequence models & Attention mechanism) —— 0.Practice questions:Sequence models & Attention mechanism

  10. csv与xlsx导出

    一.csv与xlsx格式基本介绍       csv即comma seperate values - 逗号分隔值,文件以纯文本形式来存储表格数据,它可以由任意数目的记录组成,记录之间通过某种换行符来分 ...