SQL EXISTS谓词

谓词时返回值为真值(true、false或unknown)的函数。EXISTS与其他谓词不同,它接受的参数是行的集合。

输入值为一行的谓词叫做"一阶谓词"(例如>、<、= 及 LIKE等);输入值为行的集合的谓词叫做"二阶谓词"(例如EXISTS);输入值为集合的集合的谓词叫做"三阶谓词"。SQL并不会出现三阶以上的情况。

1 实践

1.1 查找表中"不"存在的数据

图 参会信息t_meeting_records 表

需求:查找出每次会议中没有参与的人。

SELECT DISTINCT m1.meeting,m2.person
FROM t_meeting_records m1 CROSS JOIN t_meeting_records m2
WHERE NOT EXISTS
(
	SELECT *
	FROM t_meeting_records 
	WHERE meeting = m1.meeting AND person = m2.person
)

1.1.1 SQL 的集合运算

执行SQL的集合运算,需要满足下面的条件:

  1. 所有查询中的列数和列的顺序必须相同。
  2. 两个查询结果集中对应的列数据类型可以不同,但必须兼容。
  3. 两个查询结果集中的列不能包含不可比较的数据类型(例如text、blog等)。
  4. 返回的结果集的列名与操作符左侧的查询相同,ORDER BY 子句中的列名或别名必须引用左侧查询返回的列名。
  5. 不能与COMPUTE 和COMPUTE BY子句一起使用。
  6. 通过比较行来确定非重复值时,两个NULL值被视为相等。

|-----------|---------------------------------|
| EXCEPT | 获取在左侧的集合存在,但是不存在于右侧集合中的数据。 会去重。 |
| INTERSECT | 交集,会去重。 |
| UNION | 并集,UNION会去重,UNION ALL 不会去重。 |

表 SQL 的集合运算

SELECT  m1.meeting,m2.person
FROM t_meeting_records m1 CROSS JOIN t_meeting_records m2
EXCEPT 
SELECT meeting,person
FROM t_meeting_records 

1.2 肯定与双重否定转换

图 学生成绩信息t_student_grade 表

需求:查询出科目分数都在50分以上的学生。

SELECT *
FROM t_student_grade g1 
WHERE NOT EXISTS 
(
	SELECT *
	FROM t_student_grade g2 
	WHERE g2.student_id = g1.student_id AND g2.score < 50
)

需求:查处满足下列条件的学生,1)数学分数在80分以上。2)语文分数在50分以上。

SELECT student_id
FROM t_student_grade g1 
WHERE g1.`subject` IN ("数学","语文") AND NOT EXISTS 
(
	SELECT *
	FROM t_student_grade g2
	WHERE g2.student_id = g1.student_id AND 
	 1 = CASE WHEN g2.`subject` = '数学' AND g2.score < 80 THEN 1
								 WHEN g2.`subject` = '语文' AND g2.score < 50 THEN 1 
								 ELSE 0 END 
)
GROUP BY g1.student_id
HAVING COUNT(*) = 2

1.3 EXISTS 与 HAVING

图 工程进展记录信息t_project_info 表

需求:查询哪些项目已经完成到了工程1。

SELECT *
FROM t_project_info p1 
WHERE NOT EXISTS 
(
	SELECT *
	FROM t_project_info p2 
	WHERE p2.project_id = p1.project_id AND p2.status != 
	CASE WHEN p2.step_number = 0 THEN '完成'
		   WHEN p2.step_number = 1 THEN '完成'
			 ELSE '等待' END 
)
-- HAVING
SELECT project_id
FROM t_project_info 
GROUP BY project_id
HAVING COUNT(*) = SUM(
	CASE WHEN step_number <= 1 AND `status` = '完成'	THEN 1
	     WHEN step_number > 1 AND `status` = '等待' THEN 1
			 ELSE 0 END 		 
)

ESISTS 代码看起来不那么容易理解,但是性能好,而且结果包含的信息量更大。

2 练习

2.1 行结构

图 行结构表t_key_val

需求:查出value 全为1的key。

SELECT *
FROM t_key_val k1 
WHERE NOT EXISTS(
	SELECT * 
	FROM t_key_val k2 
	WHERE k2.`key` = k1.`key`
	AND (k2.value != 1 OR k2.`value` IS NULL)
);
-- HAVING
SELECT `key`
FROM t_key_val 
GROUP BY `key`
HAVING 
COUNT(*) = SUM(
	CASE WHEN `value` = 1 THEN 1 
	ELSE 0 END 
);
-- ALL
SELECT DISTINCT `key`
FROM t_key_val k1
WHERE 
1 = ALL (
	SELECT `value` FROM t_key_val k2 WHERE k2.`key` = k1.`key`
)

2.2 全称量化 ALL

需求:用ALL 完成1.3的需求。

需求:用ALL 完成1.3的需求。
-- ALL
SELECT * 
FROM t_project_info p1
WHERE 1= ALL (
	SELECT CASE WHEN p2.step_number <= 1 AND p2.`status` = '完成' THEN 1
							WHEN p2.step_number > 1 AND p2.`status` = '等待' THEN 1
							ELSE 0 END
	FROM t_project_info p2 
	WHERE p2.project_id = p1.project_id
)

2.3 求质数

图 数字集t_number 表

SELECT *
FROM t_number n1
WHERE num > 1
AND NOT EXISTS (
	SELECT *
	FROM t_number n2
	WHERE n2.num <= (n1.num / 2) AND n2.num > 1 AND MOD(n1.num,n2.num) = 0
)
相关推荐
路在脚下@26 分钟前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
苹果醋32 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
了一li2 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
码农君莫笑2 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
别致的影分身3 小时前
使用C语言连接MySQL
数据库·mysql
过过过呀Glik3 小时前
在 Ubuntu 上安装 MySQL 的详细指南
mysql·ubuntu
京东零售技术4 小时前
“慢”增长时代的企业数据体系建设:超越数据中台
数据库
sdaxue.com5 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
o(╥﹏╥)5 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
阿里嘎多学长6 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器