适合刚接触子查询的同学。用同一套「学生 / 成绩」例子,把
in和exists讲清楚。
一、它们是干什么的
在 mysql 里,in 和 exists 都常用来配合子查询做过滤:
- 先(或同时)看另一堆数据
- 再决定当前表的哪些行要留下
可以先记一句:
| 关键字 | 人话 |
|---|---|
| in | 左边这个值,在不在右边的名单里? |
| exists | 对当前这一行,括号里能不能至少找出一行? |
二、准备示例数据
学生表 students
| student_id | name |
|---|---|
| 1 | 小明 |
| 2 | 小红 |
| 3 | 小刚 |
成绩表 scores
| score_id | student_id | subject | score |
|---|---|---|---|
| 101 | 1 | 语文 | 90 |
| 102 | 1 | 数学 | 85 |
| 103 | 2 | 语文 | 92 |
结论:小明、小红有成绩;小刚没有成绩。
三、in:在不在名单里
3.1 固定名单
select * from students where student_id in (1, 2, 5);
含义:学号是 1 或 2 或 5 的学生。
- 在名单里 → 条件为真,留下
- 不在 → 为假,丢掉
3.2 名单来自子查询
需求:找出有成绩的学生。
select * from students where student_id in ( select student_id from scores );
执行直觉:
- 先跑括号:从
scores得到student_id列表,例如(1, 1, 2),相当于名单(1, 2) - 再扫
students:学号在不在名单里 - 在的留下
逐步看:
| 学生 | student_id | 在名单里? | 结果 |
|---|---|---|---|
| 小明 | 1 | 是 | 留下 |
| 小红 | 2 | 是 | 留下 |
| 小刚 | 3 | 否 | 丢掉 |
查询结果:
| student_id | name |
|---|---|
| 1 | 小明 |
| 2 | 小红 |
四、exists:存不存在关联行
同样的需求:找出有成绩的学生。
select * from students s where exists ( select 1 from scores sc where sc.student_id = s.student_id );
4.1 怎么理解
对外层每一行学生,跑一遍内层查询:
- 内层能找到至少一行 →
exists为真 → 留下这个学生 - 一行都找不到 → 为假 → 丢掉
select 1 只是占位:exists 不关心选出来的值是什么,只关心有没有行。
4.2 逐步走一遍
小明(id=1)
- 成绩表里有没有
student_id = 1?有 → 留下
小红(id=2)
- 有没有
student_id = 2?有 → 留下
小刚(id=3)
- 有没有
student_id = 3?没有 → 丢掉
结果与上面的 in 相同:小明、小红。
五、not exists:找出「没有成绩」的学生
select * from students s where not exists ( select 1 from scores sc where sc.student_id = s.student_id );
| 学生 | 有没有成绩 | not exists | 留下? |
|---|---|---|---|
| 小明 | 有 | 假 | 否 |
| 小红 | 有 | 假 | 否 |
| 小刚 | 无 | 真 | 是 |
结果:
| student_id | name |
|---|---|
| 3 | 小刚 |
也可以写成:
select * from students where student_id not in ( select student_id from scores );
在这组干净数据里,结果同样是小刚。
小提示:
not in的子查询结果里如果出现null,行为容易踩坑;很多场景更推荐not exists。入门先知道有这个差异即可。
六、in 和 exists 怎么选(入门版)
很多业务下,两者能写出等价结果,只是思路不同:
| in | exists | |
|---|---|---|
| 思考方式 | 先有一份值名单,看在不在里面 | 对当前行问:对面有没有匹配行 |
| 直观写法 | id in (1,2,3) 或 id in (子查询) | exists (带关联条件的子查询) |
| 适合 | 名单短、语义就是「属于集合」 | 语义就是「是否存在关联数据」 |
关于性能:谁更快取决于数据量、索引和优化器,不要死记「永远谁更快」。入门优先:写对、读得懂。
七、和外键的一点联系(可选)
- 外键约束:插入时就不允许指向不存在的学生
- in / exists:查询时筛选「有没有关联成绩」等
一个是写数据时的规矩,一个是查数据时的过滤手段,可以一起理解「表和表如何挂钩」。
八、一句话总结
in:值在不在这个列表里。
exists:对当前行,子查询是否至少存在一行。
not exists:对当前行,是否不存在关联行。
同一道「有成绩的学生」:
- 用
in:学号是否出现在成绩表的学号列表中 - 用
exists:该学生在成绩表里能不能找到记录
结果可以一样,想问题的角度不同。
九、练习
- 用
in查出有成绩的学生(默写一遍)。 - 用
exists再写一遍。 - 用
not exists查出没有成绩的学生。
能不看笔记写出来,这部分就算过关了。
笔记整理自零基础学习过程,示例表为 students / scores。
到此这篇关于mysql 中的 in 和 exists(零基础笔记)的文章就介绍到这了,更多相关mysql in和exists内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论