首页/数据/SQL 速查/排序中的 NULL 位置处理

排序中的 NULL 位置处理

NULL 在排序中的位置两库默认不同:MySQL 把 NULL 视为极小值(升序在前),PostgreSQL 视为极大值(升序在后),且只有 PG 支持 NULLS FIRST/LAST。

SQL 速查数据更新于 2026-10-13

空值在排序里的位置

排序时空值算大还是算小,两种数据库的默认约定正好相反:MySQL 把空值当成极小值,升序时排在最前面;PostgreSQL 把空值当成极大值,升序时排在最后面。更要紧的是语法支持不同:PostgreSQL 可以用显式子句指定空值排前还是排后,MySQL 没有这个语法,只能用表达式构造一个排序键来变通。这个差异会让同一套报表在两个数据库上输出的首尾行完全不同。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
MySQL 默认空值视为极小值,升序在前、降序在后
PostgreSQL 默认空值视为极大值,升序在后、降序在前
PostgreSQL 语法支持显式指定空值排在前面或后面
MySQL 变通用判断空值的表达式构造排序键

典型使用场景

  • 排行榜展示:未填资料的用户不应该排在榜首
  • 报表导出:缺失值统一放到末尾,便于人工核对
  • 分页一致性:显式指定空值位置,避免两库输出顺序不一致
  • 从 MySQL 迁移到 PostgreSQL 后核对排序结果
  • 待办列表排序:未设置的截止时间排在最后

两库写法

两库写法
-- PostgreSQL:显式指定空值位置,语义清楚
SELECT * FROM t ORDER BY col ASC  NULLS LAST;
SELECT * FROM t ORDER BY col DESC NULLS FIRST;

-- MySQL 变通一:先按「是否为空」排,再按值排
SELECT * FROM t ORDER BY col IS NULL, col ASC;
-- 说明:判断结果为 0 或 1,非空的排前面

-- MySQL 变通二:用分支表达式构造排序键,可读性更好
SELECT * FROM t
ORDER BY CASE WHEN col IS NULL THEN 1 ELSE 0 END, col;

-- 两库通用写法:用 COALESCE 把空值替换成一个业务上合理的值
SELECT * FROM t ORDER BY COALESCE(col, '9999-12-31') ASC;

空值位置对照

数据库升序时空值位置降序时空值位置
MySQL最前(视为极小值)最后
PostgreSQL最后(视为极大值)最前
PostgreSQL 显式指定排后最后最后
PostgreSQL 显式指定排前最前最前
MySQL 变通加判断键按表达式决定按表达式决定
从 MySQL 迁到 PostgreSQL 之后,报表的首尾行常常会变。对顺序敏感的场景(榜单、导出对账文件)一定要显式指定空值位置,不要依赖默认约定。
用判断表达式构造排序键的写法比较绕,容易被后续维护者误改。建议在同一行写清注释说明意图,或者干脆统一封装成视图供多处复用。

易错点

  • 依赖默认约定:迁移数据库后首尾行的内容发生变化,榜单或对账文件出现差异却难以定位
  • 在 MySQL 里写显式空值排序子句,语句直接语法报错
  • 用判断表达式排序时不加注释,后续维护者误删判断键,空值行跑回榜首
  • 把空值替换成极大值排序却选了业务上可能出现的值,真实数据被排到错误位置
  • 多列排序时只对第一列处理空值,第二列的空值位置仍随数据库默认变化

数据来源与参考

  • MySQL 8.0 Reference Manual · ORDER BY
  • PostgreSQL Documentation · Sorting Rows
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌