想象一下,你在大学的数据库里工作,需要找出正在上特定课程的学生。比如“编程”、“数学”和“物理”。当然,你可以写一个很长的查询,像这样:
SELECT *
FROM students
WHERE course = '编程'
OR course = '数学'
OR course = '物理';
但说实话,这种写法又累又丑。幸运的是,IN 操作符可以让你把同样的查询写得又短又省事:
SELECT *
FROM students
WHERE course IN ('编程', '数学', '物理');
是不是有点像魔法?不用一堆 OR,直接让 SQL 查找在这个列表里的值。如果你想查找不在列表里的,用 NOT IN —— 查找所有不在这个列表里的。
IN 操作符的语法
这是 IN 操作符的通用语法:
SELECT 列
FROM 表
WHERE 列 IN (值1, 值2, 值3, ...);
现在我们来看几个例子。
例子 1:学习多个课程的学生
假设我们有一张 students 表:
| id | name | course |
|---|---|---|
| 1 | Anna | 编程 |
| 2 | Mello | 物理 |
| 3 | Kate | 数学 |
| 4 | Dan | 化学 |
| 5 | Olly | 生物 |
我们想找出所有正在学“编程”、“数学”或“物理”的学生。用 IN:
SELECT name, course
FROM students
WHERE course IN ('编程', '数学', '物理');
结果:
| name | course |
|---|---|
| Anna | 编程 |
| Mello | 物理 |
| Kate | 数学 |
你看,IN 操作符让事情简单多了。我们不用写一堆 OR,只要列出我们关心的值就行。
例子 2:不学某些课程的学生
现在,假如你想找出不学“编程”、“数学”和“物理”的学生。用 NOT IN:
SELECT name, course
FROM students
WHERE course NOT IN ('编程', '数学', '物理');
结果:
| name | course |
|---|---|
| Dan | 化学 |
| Olly | 生物 |
所以,NOT IN 会返回所有 course 列不在指定列表里的行。
用 IN 和 NOT IN 搭配子查询
当你需要比较两张表的数据时,IN 和 NOT IN 特别有用。比如我们有两张表:
students 表:
| id | name | course_id |
|---|---|---|
| 1 | Anna | 101 |
| 2 | Mello | 102 |
| 3 | Kate | 103 |
| 4 | Dan | 104 |
courses 表:
| id | name |
|---|---|
| 101 | 编程 |
| 102 | 物理 |
| 103 | 数学 |
| 105 | 化学 |
假设我们要找出注册了 courses 表里课程的学生。这里可以用带 IN 的子查询:
SELECT name
FROM students
WHERE course_id IN (
SELECT id
FROM courses
);
这个查询怎么工作:子查询 SELECT id FROM courses 会返回所有课程 id。然后 IN 检查 course_id 是否在这个列表里。
结果:
| name |
|---|
| Anna |
| Mello |
| Kate |
为什么 Dan 没出来?因为他的 course_id(104)不在 courses 表里。
和 NULL 一起用时的注意点
IN 有个很重要的点:如果值列表里有 NULL,可能会影响查询结果。来看个例子。
grades 表:
| student_id | course_id | grade |
|---|---|---|
| 1 | 101 | A |
| 2 | 102 | NULL |
| 3 | 103 | B |
查找成绩在 ('A', 'B', 'C') 里的学生,查询可以这样写:
SELECT student_id
FROM grades
WHERE grade IN ('A', 'B', 'C');
结果:
| student_id |
|---|
| 1 |
| 3 |
grade 列为 NULL 的那条被忽略了,因为 NULL 不算在任何列表里。
现在假如你用 NOT IN,比如:
SELECT student_id
FROM grades
WHERE grade NOT IN ('A', 'B', 'C');
你可能以为会看到 student_id = 2,但结果是空的!为啥?因为 NULL 和列表里的每个值比较时,结果都是不确定(UNKNOWN)。这种行为很容易让人懵,所以用 NOT IN 时要注意有 NULL 的列。最好加个明确的 NULL 判断:
SELECT student_id
FROM grades
WHERE grade NOT IN ('A', 'B', 'C')
OR grade IS NULL;
结果:
| student_id |
|---|
| 2 |
IN 和 NOT IN 的使用建议
用 IN 让 SQL 更易读
如果你要判断某列是不是在一堆值里,优先用 IN,别写一堆 OR。
小心 NOT IN 和 NULL
如果数据里有 NULL,可能会有意外结果。用 NOT IN 时最好加上 NULL 的处理。
用索引加速子查询
如果 IN 里用到了子查询,确保子查询里的列有索引,不然性能可能很差。
实际问题例子
想象你在一个电商系统工作。有 orders 和 users 两张表。你想找出所有从没下过单的用户。
users 表:
| id | name |
|---|---|
| 1 | Anna |
| 2 | Mello |
| 3 | Kate |
| 4 | Dan |
orders 表:
| id | user_id | total |
|---|---|---|
| 1 | 1 | 500 |
| 2 | 3 | 300 |
用 NOT IN 来解决:
SELECT name
FROM users
WHERE id NOT IN (
SELECT user_id
FROM orders
);
结果:
| name |
|---|
| Mello |
| Dan |
这个查询怎么工作:子查询 SELECT user_id FROM orders 先返回所有下过单的用户 id(1 和 3)。然后 NOT IN 把他们排除掉,只剩没下过单的(Mello 和 Dan)。
GO TO FULL VERSION