NULL在SQL中不等于任何值(包括自身),需用IS NULL/IS NOT NULL判断;COALESCE用于提供非NULL备选值,避免触发器因NULL中断或报错,但应优先通过约束和设计规避NULL。

触发器里直接比较 NULL 会失效
SQL 中 NULL 不等于任何值,包括它自己。所以像 IF NEW.status = NULL 或 WHERE old_value = NULL 这种写法永远返回 UNKNOWN,实际效果等同于 FALSE,逻辑直接跳过。
常见错误现象:触发器看似没报错,但该执行的更新/插入/拒绝操作完全没发生;日志里查不到记录,还以为是条件没命中。
- 用
IS NULL或IS NOT NULL替代等号判断 - 想把
NULL当成某个默认值参与计算或比较时,必须显式转换——这时候COALESCE才是正解 - 注意不同数据库对
COALESCE的兼容性:MySQL、PostgreSQL、SQL Server都支持;SQLite支持但行为略有差异;Oracle推荐用NVL,不过COALESCE也行
COALESCE 在触发器里的典型用法
它不是用来“修复”NULL,而是帮你定义一个可预测的 fallback 值,让后续逻辑不中断。比如插入订单时客户 ID 为空,你想自动设为“游客”;或者更新价格时新值为 NULL,你想保持旧值不变。
示例(PostgreSQL):
CREATE OR REPLACE FUNCTION update_order_total() RETURNS TRIGGER AS $$ BEGIN NEW.total := COALESCE(NEW.price, OLD.price) * COALESCE(NEW.quantity, 1); RETURN NEW; END; $$ LANGUAGE plpgsql;
-
COALESCE(NEW.price, OLD.price)表示:如果新价格是NULL,就取老价格;否则用新价格 - 第二个参数不能是表达式(如
OLD.price + 0),必须是字面量或列名,否则部分数据库(如 MySQL 5.7)会报错 - 所有参数类型要兼容,否则触发器创建失败;例如
COALESCE(NEW.name, 123)在多数引擎中会类型冲突
用 COALESCE 防止触发器因 NULL 报错
有些操作本身不接受 NULL,比如字符串拼接、数值运算、函数入参(如 UPPER()、LENGTH())。在触发器里直接传 NULL 可能导致整个事务回滚。
常见错误现象:ERROR: function upper(unknown) does not exist 或 ERROR: null value in column violates not-null constraint,但错误位置指向触发器内部,不容易定位。
- 对可能为
NULL的字段做函数处理前,先用COALESCE包一层,例如UPPER(COALESCE(NEW.email, '')) - 不要写
COALESCE(NEW.email, '')然后紧接着做LENGTH(NEW.email)——这时用的还是原始NEW.email,得写成LENGTH(COALESCE(NEW.email, '')) - 在
BEFORE INSERT触发器中,OLD是不可用的,所以COALESCE(NEW.field, DEFAULT_VALUE)是唯一选择;别误用OLD.field
性能和可读性容易被忽略的点
COALESCE 本身开销极小,但滥用会让逻辑变绕,尤其嵌套多层时。更麻烦的是,它掩盖了数据本应不为空的事实——你本该在应用层或约束层拦截 NULL,而不是在触发器里兜底。
- 如果频繁靠
COALESCE补救,说明表设计或上游写入逻辑有问题,建议回头检查NOT NULL约束和默认值设置 -
COALESCE(a, b, c, d)是从左到右求值,第一个非NULL就返回,后面的不执行;这点在有副作用的表达式里(比如子查询)要格外小心 - MySQL 中
COALESCE返回值类型由参数中“最高优先级”的类型决定,可能导致隐式转换,比如COALESCE('1', 2)返回字符串'1',而非整数
真正难的不是写对 COALESCE,而是判断该不该在这里用它——很多时候,NULL 是信号,不是数据。










