写逻辑函数的文章,如果只列一堆函数名和例子,那是说明书,不是实战。先讲一个我几乎每个月都会遇到的SQL问题:业务表里有个逻辑删除字段 deleted,如果没特殊处理,这列是允许为 NULL 的。同事写查询时图省事,条件是 WHERE deleted <> 1,结果列表里有一批已删除用户死活查不出来。他第一反应是数据被清了,最后发现是 deleted IS NULL 的那些行全被过滤掉了。
类似的坑在 MySQL 里太常见了,而根源往往不是函数不会写,而是没把 SQL 的三值逻辑和“逻辑函数是什么时候派上用场”想清楚。这篇我会把 MySQL 逻辑函数(IF、IFNULL、NULLIF、CASE WHEN 等)逐个拆开,配套报表、更新、排序、NOT IN 排错这些真实场景讲,重点放在为什么这样写、哪些地方会翻车。适合正在学 MySQL 函数的人,也适合被 NULL 条件坑过、想彻底搞懂条件的同学。
1. SQL里的“逻辑”和代码逻辑,差别就在NULL上
很多写了两三年 SQL 的人,被问“哪个值既不等于1也不等于2,同时也不等于任何值”,反应都是愣一下。这个问题的答案是 NULL。
1.1 一张真值表说清三值逻辑
常规编程语言里,条件判断通常只有 true 和 false 两个值。但 SQL 是处理数据的,数据天然存在“缺失”和“未知”,所以 SQL 的逻辑判断有三个结果:TRUE、FALSE、UNKNOWN(在 MySQL 里 UNKNOWN 和 NULL 在许多语境下是同一个结果)。下面是 MySQL 中 AND 和 OR 的真值表,这个表值得死死记住:
| A AND B | TRUE | FALSE | NULL |
|---|---|---|---|
| TRUE | TRUE | FALSE | NULL |
| FALSE | FALSE | FALSE | FALSE |
| NULL | NULL | FALSE | NULL |
| A OR B | TRUE | FALSE | NULL |
|---|---|---|---|
| TRUE | TRUE | TRUE | TRUE |
| FALSE | TRUE | FALSE | NULL |
| NULL | TRUE | NULL | NULL |
NOT 也遵循三值逻辑:NOT TRUE 是 FALSE,NOT FALSE 是 TRUE,NOT NULL 仍然是 NULL。
为什么这条这么重要?因为很多“看着很对”的查询条件,一旦遇到 NULL,结果就不是你预期的。比如 NOT IN、<>、NOT EXISTS 这些语法,在普通程序员脑子里是“不是这个就是那个”,但在 SQL 里因为 NULL 的存在,会静默地丢掉数据。
1.2 为什么说 “= NULL” 是初学者最经典的错误
WHERE name = NULL 不会报错,但永远查不出任何一行。原因是 NULL = NULL 的结果不是 TRUE,而是 NULL(UNKNOWN)。NULL 不代表空字符串,也不代表 0,它代表“这个值是未知的”。一个未知值跟另一个未知值比较,结果当然还是未知。
我见过有人为了让这个条件“生效”,把写法改成 WHERE name = 'NULL',那是在用字符串匹配,一旦列里真的有 'NULL' 字样,又会产生脏数据。正确的判空写法只有两种:
sql复制WHERE name IS NULL;
WHERE name IS NOT NULL;
MySQL 还有一个安全等于 <=>,它专门处理 NULL 比较:
sql复制SELECT 1 <=> 1; -- 1
SELECT NULL <=> NULL; -- 1
SELECT NULL = NULL; -- NULL
<=> 的执行效率在普通场景下没有明显差异,它的真正意义是能让你在表达式里直接处理 NULL,而不需要把 IS NULL 和等值判断拆成两段。
1.3 WHERE 子句对 UNKNOWN 的处理,是决定“漏数据”的关键
WHERE 子句有个很隐蔽的规则:只返回条件结果为 TRUE 的行。条件结果是 FALSE 或 NULL(UNKNOWN)的行都会被过滤掉。
所以 WHERE deleted <> 1 想表达“没有删除的数据”,看起来没问题,但当某一行的 deleted 是 NULL 时,NULL <> 1 的结果是 NULL,这一行就被静默过滤了。如果你再写成 WHERE NOT (deleted = 1),同样有问题,因为 NOT NULL 还是 NULL。
想查“未删除”的数据,严谨写法是:
sql复制WHERE deleted = 0 OR deleted IS NULL;
或者干脆在建表时把 deleted 设计成 NOT NULL DEFAULT 0,后面所有查询都不需要再处理 NULL 这个分支。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. IF、IFNULL、NULLIF、CASE WHEN到底怎么分工
在 MySQL 中,逻辑函数做的事情本质上是“根据某个条件是 TRUE、FALSE 还是 NULL,返回不同的值”。把这些函数放一起对比,才能用得顺手。
2.1 IF()函数:条件表达式里的三目运算符
MySQL 的 IF() 是表达式,不是流程控制语句,语法如下:
sql复制IF(expr1, expr2, expr3)
如果 expr1 为 TRUE(在 MySQL 中,非 0 且非 NULL 视为 TRUE),返回 expr2,否则返回 expr3。它很像 Java 里的三元运算符:
sql复制SELECT name, IF(gender = 1, '男', '女') AS gender_name
FROM user;
一个非常容易踩的坑是拿 NULL 当条件本身:
sql复制-- 这样写永远返回 e
