百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

SQL进阶技能——集合运算(表的加减法)

bigegpt 2024-09-02 16:38 4 浏览

一:集合运算

1 表的加减法

1.1 什么是集合运算

集合在数学领域表示“各种各样的事物的总和”, 在数据库领域表示记录的集合. 具体来说,表、视图和查询的执行结果都是记录的集合, 其中的元素为表或者查询结果中的每一行。

在标准 SQL 中, 分别对检索结果使用 UNION, INTERSECT, EXCEPT 来将检索结果进行并,交和差运算, 像UNION,INTERSECT, EXCEPT这种用来进行集合运算的运算符称为集合运算符。

以下的文氏图展示了几种集合的基本运算。




[图片来源于网络]

在数据库中, 所有的表--以及查询结果--都可以视为集合, 因此也可以把表视为集合进行上述集合运算, 在很多时候, 这种抽象非常有助于对复杂查询问题给出一个可行的思路。

1.2 表的加法--UNION

1.2.1 UNION

建表代码及数据导入请使用第一章提供的代码。

接下来我们演示UNION的具体用法及查询结果:

SELECT product_id, product_name
  FROM product
 UNION
SELECT product_id, product_name
  FROM product2;

上述结果包含了两张表中的全部商品. 你会发现,这就是我们在学校学过的集合中的并集运算,通过文氏图会看得更清晰(图 7-1):



通过观察可以发现,商品编号为“ 0001 ”~“ 0003 ”的 3 条记录在两个表中都存在,因此大家可能会认为结果中会出现重复的记录,但是 UNION 等集合运算符通常都会除去重复的记录

上述查询是对不同的两张表进行求并集运算. 对于同一张表, 实际上也是可以进行求并集的。

练习题:

假设连锁店想要增加毛利率超过 50%或者售价低于 800 的货物的存货量, 请使用 UNION 对分别满足上述两个条件的商品的查询结果求并集。

结果应该类似于:


?


-- 参考答案:
SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM PRODUCT 
 WHERE sale_price<800
  
 UNION
 
SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM PRODUCT 
 WHERE sale_price>1.5*purchase_price;

思考: 如果不使用 UNION 该怎么写查询语句?

-- 参考答案:
SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM PRODUCT 
 WHERE sale_price < 800 
    OR sale_price > 1.5 * purchase_price;

1.2.2 UNION 与 OR 谓词

对于上边的练习题, 如果你已经正确地写出来查询, 你会发现, 使用 UNION 对两个查询结果取并集, 和在一个查询中使用 WHERE 子句, 然后使用 OR 谓词连接两个查询条件, 能够得到相同的结果。

那么是不是就没必要引入 UNION 了呢? 当然不是这样的. 确实, 对于同一个表的两个不同的筛选结果集, 使用 UNION 对两个结果集取并集, 和把两个子查询的筛选条件用 OR 谓词连接, 会得到相同的结果, 但倘若要将两个不同的表中的结果合并在一起, 就不得不使用 UNION 了.。

而且, 即便是对于同一张表, 有时也会出于查询效率方面的因素来使用 UNION。

练习题 :

分别使用 UNION 或者 OR 谓词,找出毛利率不足 30%或毛利率未知的商品。

参考答案:

-- 使用 OR 谓词
SELECT * 
  FROM Product 
 WHERE sale_price / purchase_price < 1.3 
    OR sale_price / purchase_price IS NULL;
-- 使用 UNION
SELECT * 
  FROM Product 
 WHERE sale_price / purchase_price < 1.3
 
 UNION
SELECT * 
  FROM Product 
 WHERE sale_price / purchase_price IS NULL;

1.2.3 包含重复行的集合运算 UNION ALL

在1.1 中我们发现, SQL 语句的 UNION 会对两个查询的结果集进行合并和去重, 这种去重不仅会去掉两个结果集相互重复的, 还会去掉一个结果集中的重复行. 但在实践中有时候需要需要不去重的并集, 在 UNION 的结果中保留重复行的语法其实非常简单,只需要在 UNION 后面添加 ALL 关键字就可以了。

例如, 想要知道 product 和 product2 中所包含的商品种类及每种商品的数量, 第一步,就需要将两个表的商品种类字段选出来, 然后使用 UNION ALL 进行不去重地合并. 接下来再对两个表的结果按 product_type 字段分组计数。

-- 保留重复行
SELECT product_id, product_name
  FROM Product
 UNION ALL
SELECT product_id, product_name
  FROM Product2;

查询结果如下:



练习题:

商店决定对product表中利润低于50% 或者 售价低于1000的商品提价, 请使用UNION ALL 语句将分别满足上述两个条件的结果取并集. 查询结果类似下表:



参考答案

SELECT * 
  FROM Product 
 WHERE sale_price < 1000
 UNION ALL
SELECT * 
  FROM Product 
 WHERE sale_price < 1.5 * purchase_price

1.2.4 隐式数据类型转换

通常来说, 我们会把类型完全一致, 并且代表相同属性的列使用 UNION 合并到一起显示, 但有时候, 即使数据类型不完全相同, 也会通过隐式类型转换来将两个类型不同的列放在一列里显示, 例如字符串和数值类型:

SELECT product_id, product_name, '1'
  FROM Product
 UNION
SELECT product_id, product_name,sale_price
  FROM Product2;

上述查询能够正确执行,得到如下结果:


?


需要注意的是 hive中进行join关联时,关联列要避免使用隐式数据类型转换,否则容易导致数据倾斜

练习题:

使用 SYSDATE()函数可以返回当前日期时间, 是一个日期时间类型的数据, 试测试该数据类型和数值,字符串等类型的兼容性。

例如, 以下代码可以正确执行, 说明时间日期类型和字符串,数值以及缺失值均能兼容。

SELECT SYSDATE(), SYSDATE(), SYSDATE()
 
 UNION
 
SELECT 'chars', 123,  null

上述代码的查询结果:


?

1.3 MySQL 8.0 不支持交运算INTERSECT

集合的交, 就是两个集合的公共部分, 由于集合元素的互异性, 集合的交只需通过文氏图就可以很直观地看到它的意义。

虽然集合的交运算在SQL标准中已经出现多年了, 然而很遗憾的是, 截止到 MySQL 8.0 版本, MySQL 仍然不支持 INTERSECT 操作。

SELECT product_id, product_name
  FROM Product
  
INTERSECT
SELECT product_id, product_name
  FROM Product2

错误代码:1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT product_id, product_name FROM Product2

此时需要用 inner join 来求得交集

SELECT p1.product_id, p1.product_name
  FROM Product p1
INNER JOIN Product2 p2
ON p1.product_id=p2.product_id

1.4 差集,补集与表的减法

求集合差集的减法运算和实数的减法运算有些不同, 当使用一个集合A减去另一个集合B的时候,对于只存在于集合B而不存在于集合A的元素, 采取直接忽略的策略,因此集合A和B做减法只是将集合A中也同时属于集合B的元素减掉。


?


1.4.1 MySQL 8.0 还不支持 EXCEPT 运算

MySQL 8.0 还不支持 表的减法运算符 EXCEPT. 不过, 借助第六章学过的NOT IN 谓词, 我们同样可以实现表的减法。

练习题:

找出只存在于Product表但不存在于Product2表的商品。

-- 使用 NOT IN 子句的实现方法
SELECT * 
  FROM Product
 WHERE product_id NOT IN (SELECT product_id 
                            FROM Product2)

1.4.2 EXCEPT 与 NOT 谓词

通过上述练习题的MySQL解法, 我们发现, 使用 NOT IN 谓词, 基本上可以实现和SQL标准语法中的EXCEPT运算相同的效果。

练习题:

使用NOT谓词进行集合的减法运算, 求出Product表中, 售价高于2000,但利润低于30%的商品, 结果应该如下表所示。


?


参考答案:

SELECT * 
  FROM Product
 WHERE sale_price > 2000 
   AND product_id NOT IN (SELECT product_id 
                            FROM Product 
                           WHERE sale_price<1.3*purchase_price)

1.4.3 INTERSECT 与 AND 谓词

对于同一个表的两个查询结果而言, 他们的交INTERSECT实际上可以等价地将两个查询的检索条件用AND谓词连接来实现。

练习题:

使用AND谓词查找product表中利润率高于50%,并且售价低于1500的商品,查询结果如下所示。


参考答案

SELECT * 
  FROM Product
 WHERE sale_price > 1.5 * purchase_price 
   AND sale_price < 1500

1.1.5 对称差

两个集合A,B的对称差是指那些仅属于A或仅属于B的元素构成的集合. 对称差也是个非常基础的运算, 例如, 两个集合的交就可以看作是两个集合的并去掉两个集合的对称差.上述方法在其他数据库里也可以用来简单地实现表或查询结果的对称差运算: 首先使用UNION求两个表的并集, 然后使用INTERSECT求两个表的交集, 然后用并集减去交集, 就得到了对称差。

但由于在MySQL 8.0 里, 由于两个表或查询结果的并不能直接求出来, 因此并不适合使用上述思路来求对称差. 好在还有差集运算可以使用. 从直观上就能看出来, 两个集合的对称差等于 A-B并上B-A, 因此实践中可以用这个思路来求对称差。

练习题:

使用Product表和Product2表的对称差来查询哪些商品只在其中一张表, 结果类似于:


?


提示: 使用 NOT IN 实现两个表的差集.

参考答案:

-- 使用 NOT IN 实现两个表的差集
SELECT * 
  FROM Product
 WHERE product_id NOT IN (SELECT product_id FROM Product2)
UNION
SELECT * 
  FROM Product2
 WHERE product_id NOT IN (SELECT product_id FROM Product)

1.5.1 借助并集和差集迂回实现交集运算 INTERSECT

通过观察集合运算的文氏图, 我们发现, 两个集合的交可以看作是两个集合的并去掉两个集合的对称差。

相关推荐

一条命令搞定pip国内镜像源设置(pip install 指定镜像)

玩python的同学想必没有不用pip的吧,pip是python包管理工具,和Nodejs的npm、Java的maven类似,这些依靠开源力量建立起的庞大软件库极大提高了开发的效率,不过默认pytho...

Cadence Allegro在PCB中手动或者自动添加差分对属性

设计PCB过程中,若设计中有差分对信号,则需要将是差分的2个信号设置为差分对,设置差分对有2种方式:手动添加及自动添加一、手动添加差分对:1、点击Setup-Constraints-Constrain...

合亿 Gutab 三防|车载工业平板功能介绍,车载工业平板厂家推荐

在商用车队管理迈向智能化、特种车辆作业追求高效化的今天,车载工业平板早已突破传统“车载导航”的单一功能,成为连接车辆、司机与云端管理的核心枢纽。从物流运输的实时调度中枢,到矿山开采的无人驾驶控制器,再...

「探长分享-黑匣子」本田冠道 2020款

【品牌】探长360汽车黑匣子【产品型号】2TPro【安装车型】本田冠道2020款【功能特点】360全景安全辅助,行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,震动监控,一步标...

「探长分享-黑匣子」奥迪A6L 2019款

【品牌】探长360汽车黑匣子【产品型号】2TPro【安装车型】奥迪A6L2019款【功能特点】360全景安全辅助,行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,震动监控,一步...

探长360全景案例分享:奥迪Q7 2011款360全景效果展示

【品牌】DCT360汽车黑匣子【产品型号】3TPro【安装车型】奥迪Q72011款【功能特点】360全景安全辅助,四路行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,24小时停...

「探长分享-黑匣子」保时捷Cayenne 2015款

【品牌】探长360汽车黑匣子【产品型号】4TPro【安装车型】保时捷Cayenne2015款【功能特点】360全景安全辅助,四路行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,...

苍蝇再小也是肉,变态电路的大阳巧客S2差点难死大神

这台大阳巧客S2电动四轮车是我家第二台四轮俱全的篷车!哈哈!大阳巧客S2配置4.5Kw永磁同步电机,SVPWM矢量控制正弦波系统,车辆在加速、爬坡上性能有提升,效率高,操控灵敏。这台车前段时间刚更换了...

「探长分享-黑匣子」奥迪Q5L 2020款

360汽车黑匣子【产品型号】4TPro【安装车型】奥迪Q5L2020款【功能特点】360全景安全辅助,四路行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,24小时停车监控,一秒一...

「探长分享-黑匣子」丰田兰德酷路泽 2016款

【品牌】探长360汽车黑匣子【产品型号】3TPro【安装车型】丰田兰德酷路泽2016款【功能特点】360全景安全辅助,四路行车录像,极致高清摄像头,模拟/数字高清/AHD多种信号格式输出,24小...

驾驶室盲区是酿成重卡事故主因?后视系统:这个锅我不背

小时候家中长辈常常提醒:离大货车远一点!司机根本看不到你!早期的货车可能真的存在驾驶盲区,比如车辆正下方,因驾驶座过高,恰好是司机看不到的视野盲区。而如今的重卡在环视系统上已经非常完善,是否还存在驾驶...

前后双录,360 G580行车记录仪(360行车记录仪g580s)

相信每一位车主都会为爱车安装行车记录仪,行车记录仪的作用不仅能为交通事故还原证据,还能防止碰瓷。传统的单镜头行车记录仪只能拍摄车头方向的行车画面,如果遇到后方车辆故意碰瓷的事故时,没有监控和后摄画面则...

海康威视同轴录像机怎么使用,海康XVR配置说明

海康威视同轴录像机支持模拟、同轴以及数字IP摄像机接入,因此在使用多种类型摄像机、老久监控项目改造等场景广泛使用。首先,新录像机第一次使用需要设置管理密码激活,密码需由8-16位数字、小写字母、大写...

亿道三防2代工业级车载平板电脑震撼登场,农机矿车专用

亿道三防近日推出2024年全新2代车载平板电脑V12R,引领多项技术创新和升级,为农机、矿车等车载领域带来了超越期待与想象的震撼体验。V12R是一款从里到外,性能、功能全线拉满的工业级车载平板电脑!拥...

分析神州十八号返回舱内的摄像机最有可能是什么类型的摄像头

有没有发现,神州十八号返回舱内摄像机的图像虽然清晰度不是很高,但是画面非常干净,没有一点干扰,几乎看不到噪点。图像清晰度不高不太可能是镜头原因,很可能是图像传感器的分辨率比较低的原因,图像传感器分辨率...