PostgreSQL和Oracle默认NULLS FIRST(ASC/DESC均排最前),SQL Server ASC时NULL排最前、DESC时排最后,MySQL 8.0+默认NULL视为最大值(ASC排最后),各库行为不一且SQL标准未强制规定。

ORDER BY 中 NULL 默认排最前是数据库实现差异,不是 SQL 标准规定
SQL 标准没强制 NULL 的排序位置,各数据库按自己理解实现:PostgreSQL 和 Oracle 默认 NULLS FIRST(升序降序都排最前),SQL Server 实际行为是 ASC 时排最前、DESC 时排最后,而 MySQL 8.0+ 默认把 NULL 当最大值处理(ASC 时排最后,但早期版本不一致)。你看到“排最前”,大概率是在 PostgreSQL 或 Oracle 上执行了 ORDER BY col DESC——它们把 NULL 当作“比所有非空值都大”,所以降序时反而顶到开头。
窗口函数的行号完全依赖这个默认顺序
ROW_NUMBER()、RANK() 这些函数不自己排序,只按 ORDER BY 输出的逻辑顺序编号。如果没写 NULLS LAST,数据库就用默认规则安置 NULL 行,结果直接进编号序列:
- 在
ORDER BY updated_at DESC下,NULL 行被排第一 →ROW_NUMBER() = 1 - 业务误以为这是“最新记录”,实际可能是未填写时间的脏数据
-
RANK()会把多个 NULL 视为相同值,一起得排名 1,后续跳号
MySQL 和 SQL Server 不支持 NULLS LAST 时怎么避免排最前
MySQL 5.7、SQL Server 2019 及更早版本不认 NULLS LAST,硬写直接报错。必须用两层排序兜底:
- 要让 NULL 排最后(等效
ORDER BY col DESC NULLS LAST):ORDER BY CASE WHEN col IS NULL THEN 1 ELSE 0 END, col DESC - 别用
IF(col IS NULL, 'ZZZZ', col)补字符串——类型不匹配或值冲突会导致乱序 - 注意:这种写法无法走索引,大数据量时性能下降明显
真正容易被忽略的是多字段排序中 NULLS LAST 的作用范围
NULLS LAST 只绑定它前面**紧邻的一个排序表达式**,不是整条 ORDER BY 都生效:
- ✅ 正确:
ORDER BY department NULLS LAST, salary DESC——department的 NULL 被控在最后,salary按默认规则 - ❌ 错误:
ORDER BY department, salary DESC NULLS LAST——NULLS LAST只管salary,department仍可能把 NULL 排最前
跨库部署时,哪怕只漏了一个字段的 NULLS LAST,就可能导致分组内行序漂移,LAG() 取到的就不是你预期的“上一行”。










