咨询空值后置排序SQL查询运行逻辑(重点解析ORDER BY部分)
对应查询代码为:
select custid , region from sales.Customers order by case when region is null then 1 else 0 end , region
1. 源数据读取环节
SQL引擎首先执行FROM sales.Customers逻辑,从销售架构下的客户表中读取全量符合基础条件的记录(本查询无WHERE筛选子句,即读取全表),仅提取后续需要用到的custid(客户ID)、region(所属区域)两个字段的值。这个阶段拿到的是完全无序的原始客户数据,不会做任何排序、过滤操作。
2. 核心:ORDER BY 排序环节工作原理
这部分是实现“NULL区域记录排在所有非空记录之后”业务目标的关键,SQL的排序逻辑完全按照ORDER BY子句后列出的两个排序键,从前到后依次生效,优先级从高到低:
第一层级排序规则:case when region is null then 1 else 0 end
SQL引擎会在排序阶段为每一条原始记录动态计算一个临时排序标记:
- 当记录的
region字段值为NULL时,计算结果为1 - 当记录的
region字段值为非空时,计算结果为0
由于SQL排序默认采用升序规则(从小到大排列),数值更小的0(非空区域记录)会整体排在数值更大的1(NULL区域记录)之前,从规则层面直接把NULL记录和非空记录拆成两大块,把NULL记录整体挪到了非空记录的后面。
补充说明:不同数据库对NULL值的默认排序规则不统一,比如SQL Server默认NULL值被识别为比所有非空值更小,会直接出现在结果集最前面;用这个CASE表达式做自定义标记的写法,是跨所有数据库通用的、不依赖数据库原生NULL排序规则的实现方式。
第二层级排序规则:region
当第一层级排序规则的计算值相同时,系统会按照第二个排序键的规则做细分排序:
- 所有非空区域的记录,第一层级标记都是
0,无法靠第一规则区分先后,此时会按照region字段本身的字典序升序排列:比如North区域的记录会排在South区域之前,同属一个区域的客户记录会被聚合到一起。 - 所有区域为NULL的记录,第一层级标记都是
1,且这类记录的region本身全为NULL,第二排序键对它们没有区分度,因此这部分记录会统一聚集在结果集的最后位置。
注意:这个临时计算的0/1标记仅用于排序环节,不会出现在最终返回的结果集中。
3. 结果集返回环节
全量数据排序完成后,系统按照最终排好的行顺序,逐行提取custid和region字段的值返回给调用方,整个查询流程结束。
举个实际的排序效果对比,比如原始无序数据为:
| custid | region |
|---|---|
| 1 | NULL |
| 2 | North |
| 3 | South |
| 4 | NULL |
| 5 | North |
经过上述排序规则处理后,最终返回的有序结果为:
| custid | region |
|---|---|
| 2 | North |
| 5 | North |
| 3 | South |
| 1 | NULL |
| 4 | NULL |
内容的提问来源于stack exchange,提问作者Yash

