SQL集合运算

 集合论是SQL语言的根基。

1 集合运算

注意事项:

1)SQL能操作具有重复行的集合,可以通过可选项ALL来支持。

如果直接使用UNION或INTERSECT,结果里不会出现重复的行。如果想在结果里留下重复行,可以加上可选项ALL。写作UNION ALL。

集合运算符为了排除掉重复行,会默认发生排序,而加上可选项ALL之后,就不会再排序了,所以性能会提升。

2) 集合运算符有优先级。

INTERSECT比UNION和EXCEPT的优先级更高。

1.1 实践

1.1.1 检查集合相等性

图 两个集合t_table_a与t_table_b

-- UNION,如果合并后与两个集合的行数一致,则两个集合相同
SELECT CASE 
WHEN COUNT(*) = (SELECT COUNT(*) FROM t_table_a)
AND COUNT(*) = (SELECT COUNT(*) FROM t_table_b) 
THEN '集合相等'  ELSE '集合不相等' END AS res 
FROM 
(SELECT *
FROM t_table_a
UNION
SELECT *
FROM t_table_b)tmp
-- 集合运算,如果A与B的并集等于A与B的交集。 则A=B
SELECT CASE WHEN COUNT(*) = 0 THEN '相等' ELSE '不相等' END AS res
FROM 
((SELECT *
FROM t_table_a
UNION 
SELECT *
FROM t_table_b)
EXCEPT 
(
	SELECT *
	FROM t_table_a
	INTERSECT 
	SELECT *
	FROM t_table_b
))tmp;

1.1.2 用差集实现关系除法运算

图 员工技能t_emp_skills 表与技能t_skills 表及期望输出

需求:找出精通t_skills 表所有技能的员工。

-- 差集 EXCEPT
SELECT DISTINCT emp 
FROM t_emp_skills e 
WHERE NOT EXISTS 
(
	 SELECT skill
	 FROM t_skills
	 EXCEPT 
	 SELECT skill 
	 FROM t_emp_skills 
	 WHERE emp = e.emp 
);	

需求:找出刚好拥有全部技术的员工(即擅长的技能和技能表的一摸一样,不多也不少)。

SELECT emp 
FROM t_emp_skills e 
WHERE NOT EXISTS (
	(SELECT skill
	FROM t_skills 
	EXCEPT 
	SELECT skill 
	FROM t_emp_skills
	WHERE emp = e.emp)
)
GROUP BY emp 
HAVING COUNT(*) = (SELECT COUNT(*) FROM t_skills);

1.1.3 寻找相等的子集

图 供应商-零件关系t_sup_parts表及期望输出

需求:找出经营的零件在种类数和种类上都完全相同的供应商组合。

SELECT s1.sup sup1,s2.sup sup2
FROM t_sup_parts s1
CROSS JOIN t_sup_parts s2 
WHERE s1.sup < s2.sup AND s1.part = s2.part
GROUP BY s1.sup,s2.sup
HAVING COUNT(*) = (SELECT COUNT(*) FROM t_sup_parts WHERE sup = s1.sup)
AND COUNT(*) = (SELECT COUNT(*) FROM t_sup_parts WHERE sup = s2.sup);

1.1.4 高效删除重复行

图 存在重复数据的t_fruit_info表

需求:删除表中重复的数据。

-- 使用关联子查询
DELETE FROM t_fruit_info f
WHERE row_id < (
	 SELECT *
	 FROM (
		 SELECT MAX(row_id)
		 FROM t_fruit_info 
		 WHERE `name` = f.name AND price = f.price
	 ) temp
);

关联子查询性能比较差。

-- 用差集运算 
DELETE FROM t_fruit_info
WHERE row_id IN (
	SELECT * FROM 
	(
		SELECT row_id
		FROM t_fruit_info 
		EXCEPT 
		(SELECT row_id
		FROM t_fruit_info
		GROUP BY `name`,price)
	) tmp
);
-- NOT IN 求补集 
DELETE FROM t_fruit_info
WHERE row_id NOT IN (
	SELECT * FROM 
	(
		SELECT MAX(row_id)
		FROM t_fruit_info 
		GROUP BY `name`,price
	) tmp
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值