SQL:2003(ISO/IEC 9075)引入 NULLS FIRST 和 NULLS LAST 作为 ORDER BY 的显式语法元素,定义在 <null ordering> 子句(Subclause 10.10)中。这是一个可选特性(Feature T611, “Elementary OLAP operations”),实现可选择不提供该语法。该语法在 SQL:2003、SQL:2008、SQL:2011、SQL:2016、SQL:2023 各版本中持续保留。
-- ANSI 标准语法(可选特性 T611)ORDER BY col ASC NULLS FIRST -- NULL 排最前ORDER BY col DESC NULLS LAST -- NULL 排最后
MySQL
默认行为
MySQL 将 NULL 视为小于所有非 NULL 值(即 NULL 是最小值)。此行为自 MySQL 4.0.10 起一直保持一致。
排序方式
NULL 位置
ORDER BY col ASC
NULL 最前(first)
ORDER BY col DESC
NULL 最后(last)
CREATE TABLE t (a INT);INSERT INTO t VALUES (1), (NULL), (3), (2), (NULL);SELECT * FROM t ORDER BY a ASC;-- 结果: NULL, NULL, 1, 2, 3SELECT * FROM t ORDER BY a DESC;-- 结果: 3, 2, 1, NULL, NULL
NULLS FIRST / NULLS LAST 支持
MySQL 8.0.21+:完整支持 NULLS FIRST 和 NULLS LAST 语法
MySQL 8.0.21 之前:不支持,需用表达式变通
-- MySQL 8.0.21+SELECT * FROM t ORDER BY a ASC NULLS LAST; -- 1, 2, 3, NULL, NULLSELECT * FROM t ORDER BY a DESC NULLS FIRST; -- NULL, NULL, 3, 2, 1
MySQL 8.0.21 之前的兼容写法
-- ASC 时想 NULL 放最后SELECT * FROM t ORDER BY ISNULL(a), a ASC;-- DESC 时想 NULL 放最前SELECT * FROM t ORDER BY a IS NULL DESC, a DESC;
可配置性
MySQL 没有任何服务器级或会话级参数来改变 NULL 排序的默认行为。NULLS FIRST/LAST 只支持在单条 SQL 语句中使用。
索引与 NULL 排序
MySQL 的 B+Tree 索引中,NULL 值在索引中排在非 NULL 值之前(与默认排序行为一致)
IS NULL 条件可以利用索引进行查找
混合排序方向(ASC 用于非 NULL 列、DESC 用于 NULL 判定表达式)可能导致 Using filesort
Oracle
默认行为
Oracle 将 NULL 视为大于所有非 NULL 值(即 NULL 是最大值)。
排序方式
NULL 位置
ORDER BY col ASC
NULL 最后(last)
ORDER BY col DESC
NULL 最前(first)
SELECT * FROM t ORDER BY a ASC;-- 结果: 1, 2, 3, NULL, NULLSELECT * FROM t ORDER BY a DESC;-- 结果: NULL, NULL, 3, 2, 1
NULLS FIRST / NULLS LAST 支持
Oracle 早在 SQL:2003 标准之前就已原生支持 NULLS FIRST 和 NULLS LAST 语法。
-- 改变默认行为SELECT * FROM t ORDER BY a ASC NULLS FIRST; -- NULL, NULL, 1, 2, 3SELECT * FROM t ORDER BY a DESC NULLS LAST; -- 3, 2, 1, NULL, NULL
Oracle 官方文档
“NULLS FIRST 和 NULLS LAST 可显式控制 NULL 在排序中的位置。省略时,NULLS LAST 用于 ASC,NULLS FIRST 用于 DESC。“
-- 默认 ORDER_BY_NULLS_FLAG=0 时的结果SELECT * FROM t ORDER BY a ASC;-- 结果: NULL, NULL, 1, 2, 3SELECT * FROM t ORDER BY a DESC;-- 结果: NULL, NULL, 3, 2, 1 ← 注意这里 NULL 在最前面
-- MySQL 写法(依赖 NULL 排最前)ORDER BY a ASC; -- NULL 在前-- 迁移到 Oracle 需改为ORDER BY a ASC NULLS FIRST; -- 显式声明 NULL 在前-- 或检查业务逻辑是否真的需要 NULL 在前
MySQL → 达梦
-- MySQL 写法ORDER BY a ASC; -- NULL 在前(MySQL)ORDER BY a DESC; -- NULL 在后(MySQL)-- 达梦(值 0 默认):ASC 相同,DESC 不同!ORDER BY a ASC; -- NULL 在前 ✅ 与 MySQL 一致ORDER BY a DESC; -- NULL 也在前 ❌ 与 MySQL 相反!-- 推荐:要么设 ORDER_BY_NULLS_FLAG=2,要么每条 SQL 加 NULLS LASTSET SF_SET_SESSION_PARA_VALUE('ORDER_BY_NULLS_FLAG', 2);
Oracle → 达梦
-- Oracle 写法ORDER BY a ASC; -- NULL 在后-- 达梦(ORDER_BY_NULLS_FLAG=0):NULL 在前 ❌ 不同!-- 达梦(ORDER_BY_NULLS_FLAG=1):NULL 在后 ✅ 一致-- 迁移后一定记得设置参数!SP_SET_PARA_VALUE(2, 'ORDER_BY_NULLS_FLAG', 1);
可移植写法(推荐)
-- 不论目标数据库,显式指定 NULL 排序位置ORDER BY a ASC NULLS LAST; -- 明确 NULL 放最后ORDER BY a ASC NULLS FIRST; -- 明确 NULL 放最前