MySQL 中的 IN 和 EXISTS(零基础笔记)

适合刚接触子查询的同学。用同一套「学生 / 成绩」例子,把 INEXISTS 讲清楚。


一、它们是干什么的

在 MySQL 里,INEXISTS 都常用来配合子查询做过滤:

  • 先(或同时)看另一堆数据
  • 再决定当前表的哪些行要留下

可以先记一句:

关键字 人话
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 固定名单

sql 复制代码
SELECT *
FROM students
WHERE student_id IN (1, 2, 5);

含义:学号是 1 或 2 或 5 的学生。

  • 在名单里 → 条件为真,留下
  • 不在 → 为假,丢掉

3.2 名单来自子查询

需求:找出有成绩的学生

sql 复制代码
SELECT *
FROM students
WHERE student_id IN (
  SELECT student_id FROM scores
);

执行直觉:

  1. 先跑括号:从 scores 得到 student_id 列表,例如 (1, 1, 2),相当于名单 (1, 2)
  2. 再扫 students:学号在不在名单里
  3. 在的留下

逐步看:

学生 student_id 在名单里? 结果
小明 1 留下
小红 2 留下
小刚 3 丢掉

查询结果:

student_id name
1 小明
2 小红

四、EXISTS:存不存在关联行

同样的需求:找出有成绩的学生

sql 复制代码
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:找出「没有成绩」的学生

sql 复制代码
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 小刚

也可以写成:

sql 复制代码
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:该学生在成绩表里能不能找到记录

结果可以一样,想问题的角度不同。


九、练习

  1. IN 查出有成绩的学生(默写一遍)。
  2. EXISTS 再写一遍。
  3. NOT EXISTS 查出没有成绩的学生。

能不看笔记写出来,这部分就算过关了。


笔记整理自零基础学习过程,示例表为 students / scores。

相关推荐
萌新小白YXY8 小时前
SAE J1587/SAE J1708 协议笔记
笔记·单片机·嵌入式硬件
努力进修9 小时前
“数据心脏” 驱动能源自主:国产数据库支撑 Cemsol 实现固井全流程数字化闭环
数据库·人工智能·能源
IT古董9 小时前
【MES学习笔记系列】MES 推荐书籍与资源
笔记·学习
vHelios9 小时前
SQL不会写?不会找关联表?复杂SQL语句编写逻辑实现思路请查收✉
数据库·sql
一米阳光86619 小时前
软考(中级)软件设计师核心笔记(9)算法——时间复杂度与空间复杂度、查找算法、排序算法
笔记·算法·职场发展·软考·软件设计师·中级职称
米饭不加菜9 小时前
常用基本求导公式与法则(超详细推导版——上)
经验分享·笔记
DB哥讲数据库9 小时前
【ClickHouse安装教程】从零开始部署高性能列式数据库(附ClickHouse安装包)
数据库·clickhouse
TDengine (老段)10 小时前
TDengine 第三方工具 — Telegraf、Kafka Connect、Flink、Spark
大数据·数据库·物联网·flink·kafka·时序数据库·tdengine
青山是哪个青山18 小时前
LangChain 学习笔记(四):Message 与提示词模板
笔记·学习·langchain
小白勇闯网安圈18 小时前
Django 响应对象、文件上传与类视图
数据库·django·sqlite