pl/sql中null不能用=或!=比较,必须用is null/is not null;nvl要求两参数类型严格一致,不支持隐式转换;coalesce需所有参数同类型或可统一转换;null参与运算结果仍为null,nvl/coalesce不能替代逻辑意图判断。
pl/sql里null不能用=或!=比较,必须用is null
直接写 where col = null 永远不返回任何行——这不是bug,是sql标准行为。null代表“未知”,两个未知无法判断相等。常见错误现象是查询突然没结果,或者update语句没更新到预期记录。
正确做法永远是:WHERE col IS NULL 或 WHERE col IS NOT NULL。哪怕你刚用NVL包装过字段,原始列值仍是NULL,比较逻辑不会变。
NVL只支持两个参数,且第二个参数类型必须和第一个严格一致
NVL本质是“如果第一个为NULL,就返回第二个;否则返回第一个”。它不支持多层兜底,也不做隐式类型转换。
常见错误:把字符串和数字混用,比如 NVL(salary, '0') ——如果salary是NUMBER,Oracle会尝试把'0'转成数字,但一旦'0'含空格或非数字字符(如' 0 '),就会报ORA-01722: invalid number。
实操建议:
- 始终确保两个参数类型一致,宁可用
TO_CHAR或TO_NUMBER显式转换 - 别指望
NVL(col, 0)能处理col是VARCHAR2又想填数字的场景 - 如果要默认空字符串,写
NVL(col, ''),不是NVL(col, NULL)(后者等于没写)
COALESCE能链式判断多个表达式,但所有分支必须同类型或可统一转换
COALESCE按顺序求值,返回第一个非NULL的表达式结果。它比NVL灵活,但类型约束更隐蔽。
典型陷阱是混合类型导致隐式转换失败。例如:COALESCE(date_col, SYSDATE, '2024-01-01') ——前两个是DATE,第三个是字符串,Oracle会尝试把字符串转DATE,依赖当前NLS_DATE_FORMAT。一旦会话格式不匹配,就抛ORA-01861: literal does not match format string。
实操建议:
- 所有参数尽量保持同一数据类型,避免依赖隐式转换
- 日期统一用
TO_DATE,数字统一用TO_NUMBER,别让Oracle猜 - 注意短路求值:前面的表达式如果很重(比如子查询),而它常为非NULL,后面分支就不会执行——这是性能优势,也是调试盲区
NULL参与计算时整行变NULL,NVL/COALESCE不是万能补丁
写SELECT NVL(price, 0) * qty FROM orders看似安全,但如果qty本身是NULL,结果仍是NULL——NVL只管price,不拦着乘法运算中途掉链子。
更隐蔽的是聚合场景:AVG(NVL(salary, 0)) 和 AVG(salary) 结果完全不同。前者把NULL全当0算进分母,后者直接忽略NULL行。业务上可能完全扭曲人均薪资含义。
所以关键不是“该不该用NVL”,而是想清楚:你真正想表达的是“缺值即零”,还是“缺值即不参与统计”?这个意图错位,比函数选错更难排查。










