SQL进阶教程——用SQL进行集合运算(第七章)
1. 前言
集合论是SQL语言的根基——这是贯穿全书主题之一。因为他的这个特性,SQL也被称为面向集合语言。只有从集合的角度思考,才能明白SQL的强大。
但是,实际上这一点长期以来都被很多人忽略了。造成这种状况,SQL本身也是要负一定责任的。其实,在很长一段时间内,SQL连我们在高中学习过的基础的集合运算符都没有。UNION是SQL-86标准开始加入的,还算比较早,而INTERSECT和EXCEPT都是SQL-92标准才加入的。至于关系除法,更是至今还没有被标准化。
2. 集合运算的几个注意事项
- SQL能操作具有重复行的集合,可以通过可选项ALL来支持
一般的集合论是不允许集合里存在重复元素的,因此集合{1,1,2,3,3,3}和集合{1,2,3}被视为相同的集合。但是关系数据库里的表允许存在重复的行,称为多重集合。
因此,SQL的集合运算符也提供了允许重复和不允许重复的两种用法。如果直接使用UNION和INTERSECT,结果里就不会出现重复行。如果想在结果里留下重复行,可以加上可选项ALL,写作UNION ALL。
出了运算结果之外,这两种用法还有一个不同。集合运算符为了排除重复行,默认的会发生排序,而加上可选项ALL之后就不会排序,所以性能会有提升。如果不关心结果是否存在重复行,或者确认结果不会产生重复行,可以加上ALL - 集合运算符有优先级
标准SQL规定,INTERSECT比UNION和EXCEPT优先级更高。因此,当同时使用UNION和INTERSECT,又想让UNION优先执行时,必须用括号明确的指定运算顺序。 - 各个DBMS提供商在集合运算的实现程度上参差不齐
- 除法运算没有标准定义
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里还没有能直接进行关系除法运算的运算符。因此,为了进行除法运算,必须自己实现。方法比较多,其中具有代表性的是下面三个
- 嵌套使用NOT EXISTS
- 使用HAVING子句转化成一对一关系
- 把除法变成减法
- 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);
本节要点:
- 在集合运算方面,SQL的标准化进行的比较缓慢,直到现在也是实现状况因数据库不同而参差不齐,因此使用的时候需要注意
- 如果集合运算符不指定ALL可选项,重复行会被排除掉,而且这种情况还会发生排序,所以性能方面不够好
- UNION和INTERSECT都具有幂等性这一重要性质,而EXCEPT不具有幂等性
- 标准SQL没有关系除法的运算符,需要自己实现
- 判断两个集合是否相等时,可以通过幂等性或一一映射两种方法
- 使用EXCEPT可以很简单的求得补集
SQL进阶教程——用SQL进行集合运算(第七章)相关推荐
- SQL进阶教程—CASE表达式
所有的文件在SQL进阶教程 (ituring.com.cn),随书下载那里 概述 文章原址 基本写法 简单CASE表达式 SELECT CASE 列名称WHEN 匹配字符 THEN 转换字符WHEN ...
- SQL进阶教程—自链接的用法
用法 https://moonshuo.cn/posts/14085.html 可重排列,排列,组合 需求:现在我需要将这个水果的品种各个组合起来,构成一个有序对的组合 在这个过程中首先执行完毕fro ...
- 【SQL学习笔记】《SQL进阶教程》1.1
SQL进阶教程学习笔记1.1 1-1case 表达式 将已有编号方式转换为新的方式并统计 SELECT CASE pref_nameWHEN '辽宁' THEN '东北'WHEN '福建' THEN ...
- 【SQL进阶教程】第一章 case表达式
本系列基于<SQL进阶教程>(如下图)学习,实现了书中代码及练习题代码.PS:电子书请大家各自默默脚本之家. [知识点1]case表达式概述 Case表达式有简单case表达式和搜索cas ...
- 【SAP Hana】X档案:SAP HANA SQL 进阶教程
SAP HANA SQL 进阶教程 5.HANA SQL 进阶教程 (1)Databases (2)User & Role (3)Schemas (4)Tables (5)Table Inde ...
- [SQL基础教程]1-4 SQL 表的创建
[SQL基础教程]1-4 SQL 表的创建 创建数据库 语法 CREATE DATABASE <数据库名称> // example CREATE DATABASE shop; 创建表 语法 ...
- SQL 高级教程:SQL BETWEEN 操作符
SQL 高级教程:SQL BETWEEN 操作符 BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEEN 操作符 操作符 BETWEEN - AND 会 ...
- oracle sql循环判断语句怎么写,Oracle 非常详细的 PL/SQL入门教程,PL/SQL语法格式/循环语句/条件判断/异常处理...
PL/SQL入门教程目录 Oracle PL/SQL入门教程,PL/SQL语法格式/循环语句/条件判断/异常处理 一.PL/SQL简介 1.PL/SQL简介 1.PL/SQl是过程语言PL与结构化语言 ...
- 【sql注入教程】SQL注入是什么?我们如何去玩转它
[sql注入教程]SQL注入是什么?我们如何去玩转它 本文转自:i春秋社区 SQL注入攻击是黑客攻击数据库最常见手段之一.简单讲,SQL注入攻击是黑客利用网站程序漏洞,通过提交精心构造的SQL语句 ...
最新文章
- 电大计算机应用,(2016年电大)电大全国计算机应用考试网考.doc
- 无插件无 Flash HTML5 浏览器直接玩《Quake II》
- 数据结构:基数排序(Radix sort)
- 中国电信计划构建安全新平台
- boost::hana::take_while用法的测试程序
- fitbit手表中文说明书_使用机器学习预测Fitbit睡眠分数
- 一部刷爆朋友圈的5G短片,看完才知道5G多暖多重要!
- resnet的瓶颈层的子层res4b22的命名规则
- oracle建表创建约束
- Protobuf使用手册--中文版
- Linux下修改MTU值
- 关于一个App调起另一个App
- MIMO-OFDM系统原理及其关键技术
- Run-Down 保护
- TCP/IP协议分层模型详解
- 宿主机连接oracle容器_Linux虚拟机与windows宿主机oracle的连接配置
- Jabber 技 术 概 况
- jQuery 的 Sizzle 选择器
- 深度粗排模型的GMV优化实践:基于全空间-子空间联合建模的蒸馏校准模型
- centos查看DHCP租期