mysql触发器中判断null必须用is null,不可用= null;因= null返回unknown导致条件失效,须用if new.email is null then配合signal中断插入;空字符串''与null需分开处理。

MySQL触发器里不能用= NULL判断字段是否为空
直接写IF NEW.email = NULL THEN永远不成立,因为=遇到NULL返回UNKNOWN,条件直接跳过。这会导致非空校验完全失效,比如本该拦截的NULL邮箱照样插入。
必须用IS NULL:IF NEW.email IS NULL THEN。它专为NULL设计,返回明确的TRUE或FALSE。
- 对
TEXT、JSON、BLOB字段同样适用 -
''(空字符串)和NULL是两回事,需分开处理:IF NEW.email IS NULL OR NEW.email = '' THEN - 阻止插入要靠
SIGNAL SQLSTATE '45000',仅SELECT或INSERT INTO log不会中断语句
PostgreSQL触发器中字段变更检测必须用IS DISTINCT FROM
写OLD.phone != NEW.phone在NULL参与时会失效:比如OLD.phone是'123'、NEW.phone是NULL,结果不是TRUE而是UNKNOWN,整个WHEN子句不触发。
IS DISTINCT FROM把NULL当确定值处理:OLD.phone IS DISTINCT FROM NEW.phone能正确捕获'123' → NULL、NULL → '456'、NULL → NULL三类情况。
- 复合类型如
JSONB、ARRAY也支持该操作符,无需转字符串 -
WHEN子句里只允许布尔表达式,不能调用函数,所以IS DISTINCT FROM是唯一可靠选择 - 别用
NOT (OLD.x = NEW.x)替代——=本身在NULL下就不可靠
SQL Server触发器里字符串拼接遇NULL即整条变NULL
写INSERTED.name + ' - ' + INSERTED.code,只要任一字段是NULL,结果就是NULL,不是空字符串。这在BEFORE INSERT里可能直接违反NOT NULL约束导致失败。
必须对每个字段单独兜底:ISNULL(INSERTED.name, '') + ' - ' + ISNULL(INSERTED.code, '')。注意ISNULL第二参数类型要兼容第一参数,否则隐式转换报错。
- 别在最外层包一层
ISNULL(整个表达式, '')——NULL + 'xxx'在进ISNULL前已崩掉 - 更新场景下,要对比
DELETED和INSERTED:仅查INSERTED.code IS NULL无法区分“首次设空”还是“本来就是空” - 想捕获“从非空变空”,得写
DELETED.code IS NOT NULL AND INSERTED.code IS NULL
所有数据库触发器都该避开查表和嵌套IF
批量更新100行,触发器里写SELECT COUNT(*) FROM logs WHERE user_id = NEW.user_id,就会执行100次查询,性能断崖下跌。
触发器只适合轻量逻辑:自动更新updated_at、递增version、校验必填字段是否为NULL。需要关联查询或发HTTP请求的,一律挪到应用层或异步任务。
- 多个字段合并判断变更,别嵌套
IF,写成:IF NOT (OLD.status IS DISTINCT FROM NEW.status AND OLD.updated_at IS DISTINCT FROM NEW.updated_at) - MySQL里用
(安全等于)替代!=,它天然处理NULL;SQL Server里先用UPDATE(字段名)快速过滤,再显式比值 - 最容易被忽略的是变量初始化顺序——存储过程开头没
SET @var = NULL,后续SELECT col INTO @var查不到数据时,@var仍保持旧值











