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
)
相关推荐
Database_Cool_1 小时前
阿里云 RDS MySQL 降本增效实战:从规格选型到成本优化,月成本降低64%全攻略
mysql·阿里云·云计算
java_logo2 小时前
Apache Doris Docker 部署指南:实时分析数据库实战
数据库·docker·apache·doris·apache doris·轩辕镜像·docker部署doris
广州灵眸科技有限公司9 小时前
xfce桌面触摸校准:基于灵眸科技EASY-EAl-Orin-Nano
数据库·windows·科技
Cloud云卷云舒11 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
憧憬成为web高手12 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学12 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh14 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
用户713335851562414 小时前
MySQL - 事务、redo/undo 日志与 MVCC
mysql
z1234567898615 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
程序猿DD15 小时前
一个 API Key,统一调用大模型、生图和联网搜索
数据库·网关