默认情况下,MySQL和SQL Server将NULL视为“最小值”,升序时排最前、降序时排最后;PostgreSQL/Oracle则相反。业务需NULL垫底时,应显式用NULLS LAST(PG/Oracle/MySQL 8.0+支持)或CASE表达式兼容处理(如ORDER BY CASE WHEN col IS NULL THEN 1 ELSE 0 END, col)。
NULL 当作“最小值”,所以 ORDER BY column ASC 时,NULL 会排最前;DESC 时反而排最后。但业务常要「非空值优先升序,NULL 统一垫底」,这不是默认能搞定的。不同数据库对 NULLS FIRST/NULLS LAST 支持不一:PostgreSQL 支持,MySQL 8.0+ 才支持,SQL Server 和旧版 MySQL 完全不认——得靠表达式绕过。
NULL 分配一个比所有合法值都大的排序权重。例如按 price 升序,但 NULL 排最后:
ORDER BY CASE WHEN price IS NULL THEN 1 ELSE 0 END, price
说明:
CASE 先分组:非 NULL 给 0,NULL 给 1 → 保证所有非空行先于 NULL 行price 正常升序,此时只作用于 price IS NOT NULL 的行THEN 'zzzzz'(确保字典序最大),但不如数值稳妥CASE 表达式不能直接写在 SELECT 列表里再 ORDER BY 别名(部分数据库不支持),必须原样写进 ORDER BY
这两者支持标准 SQL 的 NULLS LAST,但必须紧贴在列名和方向之后,不能丢在最后:
ORDER BY price ASC NULLS LAST
错误写法:ORDER BY price ASC, NULLS LAST(这会被当成排序第二列,报错)
常见陷阱:
ERROR 1064
DESC 和 NULLS LAST,效果是「非空值降序,NULL 在末尾」,符合直觉;但 ASC NULLS LAST 才是你想要的「空值垫底」NULLS LAST,仍需回退到 CASE 方案有人试过 ORDER BY COALESCE(price, 999999),看似简单,但有硬伤:
price 是 DECIMAL(10,2),填整数 999999 可能引发隐式类型转换,某些数据库会警告或截断price = 999999,它就跟 NULL 混在一起排了,逻辑错误COALESCE(name, 'ZZZZZ') 同样危险——万一真有客户姓「ZZZZZ」呢?COALESCE() 还可能干扰索引使用,尤其当字段上有 INDEX(price) 时,表达式会让索引失效真正安全的边界处理永远基于 IS NULL 判断,而不是“塞个假值”。