1. 前言

集合论是SQL语言的根基——这是贯穿全书主题之一。因为他的这个特性,SQL也被称为面向集合语言。只有从集合的角度思考,才能明白SQL的强大。
但是,实际上这一点长期以来都被很多人忽略了。造成这种状况,SQL本身也是要负一定责任的。其实,在很长一段时间内,SQL连我们在高中学习过的基础的集合运算符都没有。UNION是SQL-86标准开始加入的,还算比较早,而INTERSECT和EXCEPT都是SQL-92标准才加入的。至于关系除法,更是至今还没有被标准化。

2. 集合运算的几个注意事项

  1. SQL能操作具有重复行的集合,可以通过可选项ALL来支持
    一般的集合论是不允许集合里存在重复元素的,因此集合{1,1,2,3,3,3}和集合{1,2,3}被视为相同的集合。但是关系数据库里的表允许存在重复的行,称为多重集合。
    因此,SQL的集合运算符也提供了允许重复和不允许重复的两种用法。如果直接使用UNION和INTERSECT,结果里就不会出现重复行。如果想在结果里留下重复行,可以加上可选项ALL,写作UNION ALL。
    出了运算结果之外,这两种用法还有一个不同。集合运算符为了排除重复行,默认的会发生排序,而加上可选项ALL之后就不会排序,所以性能会有提升。如果不关心结果是否存在重复行,或者确认结果不会产生重复行,可以加上ALL
  2. 集合运算符有优先级
    标准SQL规定,INTERSECT比UNION和EXCEPT优先级更高。因此,当同时使用UNION和INTERSECT,又想让UNION优先执行时,必须用括号明确的指定运算顺序。
  3. 各个DBMS提供商在集合运算的实现程度上参差不齐
  4. 除法运算没有标准定义

3. 比较表和表:检查集合相等性之基础表

这里说的“相等”指的是行数和列数以及内容都相同,即是“同一个集合”的意思

select count(1) row_cntfrom ( select * from tbl_Aunion select *from tbl_b) tmp
;

4. 比较表和表:检查集合相等性之进阶篇

SELECT CASE WHEN COUNT(*) = 0 THEN '相等'ELSE ‘不相等’END AS result
FROM ((SELECT * FROM TB1_AUNIONSELECT * FROM TB1_B)EXCEPT(SELECT * FROM TB1_AINTERSECTSELECT * FROM TB1_B))) TMP;
/**这个改进版本连事先查询两张表的行数这种准备工作也不需要了,但是功能改进了,
却也带来了一些缺陷。由于这里需要四次排序,所以性能会有所下降**/

5. 用差集实现关系除法运算

在本节开头说过,SQL里还没有能直接进行关系除法运算的运算符。因此,为了进行除法运算,必须自己实现。方法比较多,其中具有代表性的是下面三个

  1. 嵌套使用NOT EXISTS
  2. 使用HAVING子句转化成一对一关系
  3. 把除法变成减法
  • Skills
skill(技术)
Oracle
UNIX
Java
  • EmpSkills
emp(员工) skill(技术)
相田 Oracle
相田 UNIX
相田 Java
相田 C#
神崎 Oracle
神崎 UNIX
神崎 Java
平井 UNIX
平井 Oracle
平井 PHP
平井 Perl
平井 C++
若田部 Perl
渡来 Oracle
  • 从表EmpSkills中找出精通表Skills中所有技术的员工
--用求差的方法进行关系除法运算
select distinct empfrom empskills es1where not exists(select skill from skillsexpectselect skill from empskills es2where es1.emp = es2.emp);
/**理解这段代码的要点在于EXCEPT运算符和关联子查询。
关联子查询建立在表Empskills上,这是因为,我们要针对每个员工进行集合运算。
即从集合的技术的集合中减去每个员工自己的技术的集合,结果集合为空集
则说明该员工具备所有的需求的技术,否则说明该员工不具备某些需求的技术**/

注意:

  • 关联子查询是为了使SQL能够实现类似面向过程语言中循环的功能而引入的

6. 寻找相等的子集

  • SupParts
A 螺丝
A 螺母
A 管子
B 螺丝
B 管子
C 螺丝
C 螺母
C 管子
D 螺丝
D 管子
E 保险丝
E 螺母
E 管子
F 保险丝

这个问题看起来简单,但是SQL并没有提供任何用于检查集合的包含关系或相等性的谓词,并且比较的双方都不固定,这次我们需要比较所有子集的全部组合,所以这个问题更具有普遍性

--找出经营的零件在种类数和种类上都完全相同的供应商组合
select a.sup s1, b.sup s2from supparts a, supparts bwhere a.sup < b.sup                       -- 生成供应商的全部组合 and a.part = b.part                     -- 条件1:经营同种类型的零件 group by a.sup, b.sup
having count(*) = (select count(1)         -- 条件2:经营的零件的数量种类相同 a = 中间数from supparts cwhere c.sup = a.sup)and count(*) = (select count(1)         -- 条件2:经营的零件的数量种类相同 b = 中间数from supparts dwhere d.sup = b.sup)
/**如果我们把HAVING子句里的两个条件当初精准关系除法运算,机会很好理解
加上这两个条件,我们就能保证集合A和集合B的元素个数一致,不会出现不足或者过剩(即存在一一映射)
而且条件一又保证了经营的零件类型也都是完全相同的**/
;

7. 用于删除重复行的高效SQL

  • Products
name(商品名称) price(价格)
苹果 50
橘子 100
橘子 100
橘子 100
香蕉 80
  • 前面介绍的是使用关联子查询
DELETE FROM Product
WHERE rowid < (SELECT MAX(P2.rowid)FROM Products P2WHERE Products.name = P2.nameAND Products.price=P2.name);
/**关联子查询的性能较差(光是DELETE处理就比较耗时了)
**/
-- 删除重行高效SQL语句(1):通过EXCEPT求补集
delete from products
where rowid  in (select rowid           -- 全部rowidfrom products except                 -- 减去select max(rowid)      -- 要留下的rowidfrom productsgroup by name1, price);
-- 删除重行高效SQL语句(2):通过NOT IN求补集
delete from productswhere rowid not in (select max(rowid)from productsgroup by name1, price);

本节要点:

  1. 在集合运算方面,SQL的标准化进行的比较缓慢,直到现在也是实现状况因数据库不同而参差不齐,因此使用的时候需要注意
  2. 如果集合运算符不指定ALL可选项,重复行会被排除掉,而且这种情况还会发生排序,所以性能方面不够好
  3. UNION和INTERSECT都具有幂等性这一重要性质,而EXCEPT不具有幂等性
  4. 标准SQL没有关系除法的运算符,需要自己实现
  5. 判断两个集合是否相等时,可以通过幂等性或一一映射两种方法
  6. 使用EXCEPT可以很简单的求得补集

SQL进阶教程——用SQL进行集合运算(第七章)相关推荐

  1. SQL进阶教程—CASE表达式

    所有的文件在SQL进阶教程 (ituring.com.cn),随书下载那里 概述 文章原址 基本写法 简单CASE表达式 SELECT CASE 列名称WHEN 匹配字符 THEN 转换字符WHEN ...

  2. SQL进阶教程—自链接的用法

    用法 https://moonshuo.cn/posts/14085.html 可重排列,排列,组合 需求:现在我需要将这个水果的品种各个组合起来,构成一个有序对的组合 在这个过程中首先执行完毕fro ...

  3. 【SQL学习笔记】《SQL进阶教程》1.1

    SQL进阶教程学习笔记1.1 1-1case 表达式 将已有编号方式转换为新的方式并统计 SELECT CASE pref_nameWHEN '辽宁' THEN '东北'WHEN '福建' THEN ...

  4. 【SQL进阶教程】第一章 case表达式

    本系列基于<SQL进阶教程>(如下图)学习,实现了书中代码及练习题代码.PS:电子书请大家各自默默脚本之家. [知识点1]case表达式概述 Case表达式有简单case表达式和搜索cas ...

  5. 【SAP Hana】X档案:SAP HANA SQL 进阶教程

    SAP HANA SQL 进阶教程 5.HANA SQL 进阶教程 (1)Databases (2)User & Role (3)Schemas (4)Tables (5)Table Inde ...

  6. [SQL基础教程]1-4 SQL 表的创建

    [SQL基础教程]1-4 SQL 表的创建 创建数据库 语法 CREATE DATABASE <数据库名称> // example CREATE DATABASE shop; 创建表 语法 ...

  7. SQL 高级教程:SQL BETWEEN 操作符

    SQL 高级教程:SQL BETWEEN 操作符 BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEEN 操作符 操作符 BETWEEN - AND 会 ...

  8. oracle sql循环判断语句怎么写,Oracle 非常详细的 PL/SQL入门教程,PL/SQL语法格式/循环语句/条件判断/异常处理...

    PL/SQL入门教程目录 Oracle PL/SQL入门教程,PL/SQL语法格式/循环语句/条件判断/异常处理 一.PL/SQL简介 1.PL/SQL简介 1.PL/SQl是过程语言PL与结构化语言 ...

  9. 【sql注入教程】SQL注入是什么?我们如何去玩转它

    [sql注入教程]SQL注入是什么?我们如何去玩转它 本文转自:i春秋社区   SQL注入攻击是黑客攻击数据库最常见手段之一.简单讲,SQL注入攻击是黑客利用网站程序漏洞,通过提交精心构造的SQL语句 ...

最新文章

  1. 电大计算机应用,(2016年电大)电大全国计算机应用考试网考.doc
  2. 无插件无 Flash HTML5 浏览器直接玩《Quake II》
  3. 数据结构:基数排序(Radix sort)
  4. 中国电信计划构建安全新平台
  5. boost::hana::take_while用法的测试程序
  6. fitbit手表中文说明书_使用机器学习预测Fitbit睡眠分数
  7. 一部刷爆朋友圈的5G短片,看完才知道5G多暖多重要!
  8. resnet的瓶颈层的子层res4b22的命名规则
  9. oracle建表创建约束
  10. Protobuf使用手册--中文版
  11. Linux下修改MTU值
  12. 关于一个App调起另一个App
  13. MIMO-OFDM系统原理及其关键技术
  14. Run-Down 保护
  15. TCP/IP协议分层模型详解
  16. 宿主机连接oracle容器_Linux虚拟机与windows宿主机oracle的连接配置
  17. Jabber 技 术 概 况
  18. jQuery 的 Sizzle 选择器
  19. 深度粗排模型的GMV优化实践:基于全空间-子空间联合建模的蒸馏校准模型
  20. centos查看DHCP租期

热门文章

  1. UnityRPG游戏中的球形检测范围
  2. 【车牌识别】基于matlab GUI BP神经网络车牌识别(带面板)【含Matlab源码 790期】
  3. 不用编程超简单的自动化测试工具:Airtest安装使用入门篇
  4. php 熊掌号api,关于熊掌号资源提交功能API接口解读
  5. callfreee:纯点对点VoIP解决方案出现
  6. python作者的诗_用python和她一起唐诗宋词
  7. 彩色MT9V034摄像头 Bayer转rgb FPGA实现
  8. Web安全:XEE 实体注入
  9. MindNode,你的思维导图专家!
  10. Go学习笔记02-源码