为什么要先对NULL排序?


20

为什么当我们在列中有一个NULL值并按值升序排序时,这些NULL首先排序?

select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test

结果是

NULL
1
2
3
4

我一直认为NULL表示“不确定”或可能的“未知”。如果是这样,那么由于该值可能大于所有其他值,它们是否会排在最后?(或者这是某处的排序选项?)

我使用的是SQL Server 2008R2,但我怀疑在所有SQL Server以及所有RDBMS中都是如此。


1
Oracle最后列出了它。一次把我搞砸了,认为它的行为应该像SQL Server。
AndreiRînea2012年

2
“如果是这样的话,它们就不会排在最后,因为该值可能大于所有其他值”。该值也可能小于所有其他值。对我来说,很直观,像null这样的false值应该位于低端​​。实用,因为在实践中,您经常想使用desc顺序来显示最大或最新的东西,在这种情况下,我很乐意将空的东西放在最后。
mahemoff

数据库执行您要执行的操作。如果您知道数据包含空值,并且出于某种商业原因对数据进行某种排序,则需要在查询或处理/显示数据的代码/视图中指定该值。切勿将排序保留到默认的数据库行为。
没必要,2017年

Answers:


19

BOL:值为NULL表示该值未知。NULL值不同于空值或零值。没有两个空值相等。两个空值之间或空值与任何其他值之间的比较返回未知,因为每个空值都是未知的。

NULL表示未知。没有其他解释有效。

如果是这样,那么由于该值可能大于所有其他值,它们是否会排在最后?

没有可能。没有潜在的价值。未知未知未知。

至于为什么首先出现而不是最后出现,这是已发布的SQL标准所不能解决的,不幸的是,由RDBMS供应商自行决定:

维基百科:SQL标准没有明确定义Null的默认排序顺序。而是,在一致的系统上,可以分别通过使用ORDER BY列表的NULLS FIRST或NULLS LAST子句在所有数据值之前或之后对Null进行排序。但是,并非所有DBMS供应商都实现此功能。未实现此功能的供应商可能会为DBMS中的Null排序指定不同的处理方式。


因此,这是一个判断电话。这很有意义。谢谢!
理查德

6

您是正确的,NULL可能意味着“不确定”或“未知”或“未知”或“不适用”。但是没有理由将Null放在首位或最后。如果我们不知道实际值,那么tehy可能很小也可能很大。

我认为确定排序期间Null的所需行为的标准是:

ORDER BY 
    test NULLS LAST                      --- or NULLS FIRST for the opposite

不幸的是,SQL-Server尚未采用此语法。如果我没有记错的话,PostgreSQL和Oracle都有它。

一种解决方案:

ORDER BY 
     CASE WHEN test IS NOT NULL 
            THEN 0 
          ELSE 1 
     END 
   , test

另一个需要根据数据类型进行调整的解决方案-但不能很好地执行,因为它不能在上使用索引(test)

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer

这样,ORDER BY COALESCE(test,2147483647)SQL Server无法使用索引。
2014年

3

我不知道为什么要这样做,但是按照定义,NULLS不能与非NULLS进行比较,因此它们要么必须开头要么结尾(Mark的答案对此进行了更详细的介绍)。

要获得所需的行为-据我所知,没有将空值放在最后的排序选项,因此您必须通过使用计算列将其强制放在最后来对它进行分类。但是,在SQL Server中,CASE WHEN ...当数据包含集合运算符(UNION ALL)时,不能按计算列()进行排序。所以:

CREATE TABLE #sorttest(test int)
INSERT INTO #sorttest values(1)
INSERT INTO #sorttest values(5)
INSERT INTO #sorttest values(4)
INSERT INTO #sorttest values(NULL)
INSERT INTO #sorttest values(3)
INSERT INTO #sorttest values(2)
SELECT test
FROM #sorttest
ORDER BY CASE WHEN test IS NULL THEN 1 ELSE 0 END, test

DROP TABLE #sorttest

最后将对null进行排序。如果必须使用UNION(或EXCEPTINTERSECTS)生成数据集,则将数据如上所述转储到临时表中。


...或将UNIONed输出用作派生表。
Andriy M

0

如果要处理数字,也可以使用

ORDER BY -test DESC

NULL是可能的最低值,因此请DESC放在最后。同时,非null值的符号已反转,因此DESC实际ASC值实际上是一个。这应该比CASE我想的要快,我想查询优化器也可以在test列上使用索引。


3
不,它不能使用索引进行排序。除非您对计算表达式具有索引(- test)
ypercubeᵀᴹ

1
聪明,尽管仅限于数字数据(无论如何都适用于OP的示例)。我不确定这是否确实比使用CASE快,但是我确定它不会使用索引(除非@ypercubeᵀᴹ所说的那样–但是CASE表达式可以以完全相同的方式建立索引)。
Andriy M
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.