讲解

IN 用来判断「是否在一组候选值里」:WHERE city IN ('北京', '上海') 等价于 city = '北京' OR city = '上海',候选多的时候简洁得多。前面加 NOT 取反:WHERE status NOT IN ('paid', 'cancelled') 查出既不是已支付也不是已取消的订单。IN 的括号里还可以放另一个查询(子查询),后面有专门章节。

BETWEEN 表达「在某个区间内」:WHERE price BETWEEN 50 AND 70 表示 50 到 70 元,包含两端端点,等价于 price >= 50 AND price <= 70。对数字、字符串、ISO 日期都适用:WHERE order_date BETWEEN '2025-02-01' AND '2025-02-28' 筛出二月的订单。同样可以加 NOT 取反。

IN 有一个著名的陷阱:候选列表里混入 NULL 时,NOT IN 的结果会整个变空。原因是 NOT IN 等价于对每个候选值做 != 比较再用 AND 连接,而任何值 != NULL 的结果是 NULL(不真),AND 链上有一个不真整行就被排除。IN(不带 NOT)遇到 NULL 只是忽略它,但 NOT IN 会直接让查询「什么都查不到」。

示例

北京或上海的学生:

SELECT name, city FROM students WHERE city IN ('北京', '上海');

价格在 50 到 80 元之间(含端点)的课程:

SELECT title, price FROM courses WHERE price BETWEEN 50 AND 80 ORDER BY price;

未完结的订单(既不是已支付也不是已取消):

SELECT id, status, amount FROM orders WHERE status NOT IN ('paid', 'cancelled');

常见坑

  • 忘记 BETWEEN 包含端点:BETWEEN 1 AND 10 包含 1 和 10。统计「上个月」数据时如果写 BETWEEN '2025-01-01' AND '2025-02-01',会把 2 月 1 日零点的数据也算进来;更稳妥的写法是 >= '2025-01-01' AND < '2025-02-01'。
  • NOT IN 遇上 NULL 候选:候选集来自子查询且其中可能有 NULL 时,NOT IN 会返回空结果。用 NOT IN 前先用 IS NOT NULL 过滤候选集,或改用 NOT EXISTS。
  • IN 列表里写变量占位符的个数问题:程序里动态生成 IN (?, ?, ?) 时要按候选个数生成占位符,空列表在标准 SQL 里是语法错误,代码里要特判。
  • BETWEEN 用于不包含端点的区间:业务上「大于 18 岁」是 age > 18,写 BETWEEN 18 AND ... 会把 18 岁包含进来,先想清楚端点该不该含。

小结

IN 匹配一组候选值,BETWEEN 匹配闭区间;NOT IN 的候选里绝不能有 NULL。下一节系统讲 NULL 的处理。