SQL Server 中与 Oracle 的 NULLS FIRST 等效的语句是什么?

59

Oracle有一个NULLS FIRST选项,我可以使用它来使空值排在顶部,然后按照我的列值降序排序:

ORDER BY date_sent NULLS FIRST

在SQL Server中,什么是可比较的?假设日期值为NULL或过去日期,有以下这些选择:

ORDER BY ISNULL(date_sent, GETDATE()) DESC
ORDER BY (CASE WHEN t.setinactive IS NULL THEN 1 ELSE 2 END), t.setinactive DESC
ORDER BY -CAST(date_sent as int) ASC

还有其他的吗?


2
可能是 https://dev59.com/4HRA5IYBdhLWcg3wzhNY 的重复问题,按日期排序时先显示空值,然后是最近的日期。 - Pierre-Alain Vigeant
8个回答

82

你可以使用一些技巧:

ORDER BY (CASE WHEN [Order] IS NULL THEN 0 ELSE 1 END), [Order] 

2
通过这个技巧,你可以实现任何你想要的排序。你甚至可以模仿许多语言中发现的更通用的IComparer接口。 - usr
请记住,这会严重降低性能,如果您以前使用了索引,因为现在必须手动对结果进行排序。 - Doug S

22
简短的回答是:在必要的情况下,改变空值排序的最佳解决方案是被接受的。但你只需要在必要的情况下使用它或其变体:
- DESC + NULLS FIRST: ORDER BY (CASE WHEN [Order] IS NULL THEN 0 ELSE 1 END), [Order] DESC - ASC + NULLS LAST: ORDER BY (CASE WHEN [Order] IS NULL THEN 1 ELSE 0 END), [Order] ASC - ASC + NULLS FIRST:默认情况下可以正常工作 - DESC + NULLS LAST:默认情况下可以正常工作
让我们看一下原因:
如果您查看ORDER BY Clause (Transact-SQL) MSDN docs,并向下滚动到ASC | DESC,您可以阅读到以下内容:

ASC | DESC

指定应按升序或降序对指定列中的值进行排序。ASC按最低值到最高值排序。DESC按最高值到最低值排序。ASC是默认排序顺序。空值被视为最低可能值。

因此,默认情况下,如果您指定ASC顺序,则它的工作方式类似于NULLS FIRST。如果您指定DESC,则它的工作方式类似于NULLS LAST

因此,您只需要在DESC顺序中更改NULLS FIRST的行为,在ASC顺序中更改NULLS LAST的行为。

我个人认为,在必要的情况下更改nulls的排序方式的最佳解决方案是已接受的解决方案,但我已将其包含在我的答案开头,以适应不同的情况。


9

使用用例/When语句,例如:

ORDER BY (case WHEN ColINT IS NULL THEN {maxIntValue} ELSE ColINT END) DESC

ORDER BY (case WHEN ColVChar IS NULL THEN {maxVCharValue} ELSE ColVChar END) DESC

ORDER BY (case WHEN ColDateT IS NULL THEN {maxDateTValue} ELSE ColDateT END) DESC

...等等。

或者更好的是,您不需要关心列类型和最大值。

ORDER BY (case WHEN ColAnyType IS NULL THEN 1 ELSE 0 END) DESC, ColAnyType DESC

4
一个简单的例子:
SELECT (CASE WHEN Value1 IS NULL THEN 1 ELSE 0 END) AS ValueIsNull, Value1, Value2, Value3
FROM TableName
ORDER BY ValueIsNull DESC, Value1 

4

如果您的表中有一些日期小于当前时间,另外一些日期大于当前时间,那么NULL值会出现在列表的中间位置。相反,您应该使用一个永远不会排序到列表中间的值。

按IsNull(Date_Sent, '17530101')降序排列

注意:这个日期实际上是1753年1月1日。


按照IsNull(Date_Sent, '17530101') desc排序可以确保我的具有空date_sent值的列出现在底部,而不是顶部。你说得对,但我可不能穿越未来来设置date_sent的值=) - OMG Ponies
好的观点,但原则仍然适用。您应该使用一个在数据中不会自然出现的值。例如:按IsNull(Date_Sent,'99990101')desc排序。 - George Mastros
完全同意使用哨兵值。 - OMG Ponies

3
ORDER BY
  COALESCE(POSTING_DATE,'1900-01-01 00:00:00.000')
 ,OTHER_FIELDS

无法工作 - 空值首先出现,但是其余的date_sent列没有按照DESC顺序排序。 - OMG Ponies

3

当您想调整空值在排序顺序中的出现方式时,这是一种替代方法。否定该列并反转排序顺序。不幸的是,您需要将dateTime列进行CAST。

ORDER BY -CAST(date_sent as int) ASC

确认:空值在顶部,非空值按降序排列。 - OMG Ponies

1
据我所知,您无法控制这个。使用ISNULL是正确的方法。
对于字符串,我也使用ISNULL(field, '')来达到同样的目的。

1
Kev:这完全取决于手头问题的性质。问题并不是“在所有情况下都要使用ORDER BY子句吗?”,因此G Mastros的观点很好,但并不严格关键问题的关键路径。rexem正在寻找一种更全局的方法来控制NULL排序。 - David Andres

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接