SQL 排序时对Null值的处理,你想按照 EMP
表的 COMM 列对查询结果进行排序,但该字段可能为 Null
。因此,你需要想个办法来指定是否应该将 Null
值排到后面。
SQL 排序时对Null值的处理 问题
你想按照 EMP
表的 COMM 列对查询结果进行排序,但该字段可能为 Null
。因此,你需要想个办法来指定是否应该将 Null
值排到后面。
ENAME SAL COMM
---------- ---------- ----------
TURNER 1500 0
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
SMITH 800
JONES 2975
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
或者你希望把 Null
值放在前面。
ENAME SAL COMM
---------- ---------- ----------
SMITH 800
JONES 2975
CLARK 2450
BLAKE 2850
SCOTT 3000
KING 5000
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
MARTIN 1250 1400
WARD 1250 500
ALLEN 1600 300
TURNER 1500 0
SQL 排序时对Null值的处理 解决方案
根据你希望的排序方式(以及你所使用的数据库管理系统如何处理 Null
值排序问题),你能够对可能为 Null
的列进行升序排列或者降序排列。
select ename,sal,comm
from emp
order by 3
select ename,sal,comm
from emp
order by 3 desc
这个解决方案表明,如果一个可能为 Null
的列含有非 Null
值,它们也会相应地被升序排列或降序排列;这与你的直觉可能相反。但是,如果你希望采用与非 Null
值列不同的方式来排列 Null
值,例如,你可能想把非 Null
值以升序排列或降序排列,而把全部 Null
值都放到最后面,那么你就要使用 CASE
表达式来动态调整排序项。
DB2、MySQL、PostgreSQL 和 SQL Server
使用 CASE
表达式标记 Null
值。该标记有两种可能的取值:一种代表 Null
值,另一种代表非 Null
值。一旦你做好了标记,只要简单地把它放进 ORDER BY
子句就行了。这样一来,你就能在不影响非 Null
值的情况下,方便地调整 Null
值的位置了。
/* 非Null值COMM升序排列,全部Null值放到最后面 */
select ename,sal,comm
from (
select ename,sal,comm,
case when comm is null then 0 else 1 end as is_null
from emp
)x
order by is_nulldesc,comm
ENAME SAL COMM
------ ----- ----------
TURNER 1500 0
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
SMITH 800
JONES 2975
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
/* 非Null值COMM降序排列,全部Null值放到最后面 */
select ename,sal,comm
from (
select ename,sal,comm,
case when comm is null then 0 else 1 end as is_null
from emp
)x
order by is_nulldesc,commdesc
ENAME SAL COMM
------ ----- ----------
MARTIN 1250 1400
WARD 1250 500
ALLEN 1600 300
TURNER 1500 0
SMITH 800
JONES 2975
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
/* 非Null值COMM升序排列,全部Null值放到最前面 */
selectename,sal,comm
from (
selectename,sal,comm,
case when comm is null then 0 else 1 end as is_null
from emp
)x
order by is_null,comm
ENAME SAL COMM
------ ----- ----------
SMITH 800
JONES 2975
CLARK 2450
BLAKE 2850
SCOTT 3000
KING 5000
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
TURNER 1500 0
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
/* 非Null值COMM降序排列,全部Null值放到最前面 */
selectename,sal,comm
from (
selectename,sal,comm,
case when comm is null then 0 else 1 end as is_null
from emp
)x
order by is_null,comm desc
ENAME SAL COMM
------ ----- ----------
SMITH 800
JONES 2975
CLARK 2450
BLAKE 2850
SCOTT 3000
KING 5000
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
MARTIN 1250 1400
WARD 1250 500
ALLEN 1600 300
TURNER 1500 0
Oracle
如果你使用的是 Oracle 8i 或者更早的版本,可以使用上述针对其他平台的解决方案。如果使用的是 Oracle 9i 及后续版本,则能使用针对 ORDER BY
子句的扩展语法 NULLS FIRST
和 NULLS LAST
来决定 Null
值应该排到前面还是后面,而无须考虑非 Null
值的排序方式。
/* 非Null值COMM升序排列,全部Null值放到最后面 */
select ename,sal,comm
from emp
order by comm nulls last
ENAME SAL COMM
------ ----- ----------
TURNER 1500 0
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
SMITH 800
JONES 2975
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
/* 非Null值COMM降序排列,全部Null值放到最后面 */
select ename,sal,comm
from emp
order by commdesc nulls last
ENAME SAL COMM
------ ----- ----------
MARTIN 1250 1400
WARD 1250 500
ALLEN 1600 300
TURNER 1500 0
SMITH 800
JONES 2975
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
/* 非Null值COMM升序排列,全部Null值放到最前面 */
select ename,sal,comm
from emp
order by comm nulls first
ENAME SAL COMM
------ ----- ----------
SMITH 800
JONES 2975
CLARK 2450
BLAKE 2850
SCOTT 3000
KING 5000
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
TURNER 1500 0
ALLEN 1600 300
WARD 1250 500
MARTIN 1250 1400
/* 非Null值COMM降序排列,全部Null值放到最前面 */
select ename,sal,comm
from emp
order by commdesc nulls first
ENAME SAL COMM
------ ----- ----------
SMITH 800
JONES 2975
CLARK 2450
BLAKE 2850
SCOTT 3000
KING 5000
JAMES 950
MILLER 1300
FORD 3000
ADAMS 1100
MARTIN 1250 1400
WARD 1250 500
ALLEN 1600 300
TURNER 1500 0
SQL 排序时对Null值的处理 扩展知识
除非数据库管理系统提供了一种方式,它能够让你在无须修改非 Null
值数据的情况下方便地把 Null
值排到最前面或者最后面(像 Oracle 那样),否则你就得添加一个辅助列。
辅助列(只存在于查询语句里,而不存在于表中)的目的是,让你能够识别出 Null
值,并控制其排在最前面还是最后面。对于非 Oracle 解决方案的查询语句,其内嵌视图 X
会返回如下结果集。
select ename,sal,comm,
case when comm is null then 0 else 1 end as is_null
from emp
ENAME SAL COMM IS_NULL
------ ----- ---------- ----------
SMITH 800 0
ALLEN 1600 300 1
WARD 1250 500 1
JONES 2975 0
MARTIN 1250 1400 1
BLAKE 2850 0
CLARK 2450 0
SCOTT 3000 0
KING 5000 0
TURNER 1500 0 1
ADAMS 1100 0
JAMES 950 0
FORD 3000 0
MILLER 1300 0
通过使用 IS_NULL
返回的值,你就能在不影响 COMM
排序的情况下,轻而易举地把全部 Null
值放到最前面或者最后面。