SQL如何使空值升序排序时最后


297

我有一个带日期时间字段的SQL表。有问题的字段可以为空。我有一个查询,我希望结果按datetime字段升序排序,但是我希望datetime字段在列表的末尾而不是开头的行为null。

有没有简单的方法可以做到这一点?



Answers:


394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate

2
但是请注意,如果将索引放在sort列上以提高性能(*),则此方法将使查询计划复杂化,并失去很多性能优势。*-索引提供了预先排序的数据,因此避免了每次查询执行的排序。建议尽可能过滤掉NULL记录,以完全避免此问题。
redcalx 2012年

2
尼斯的答案也给这里用的优势和劣势一切可能的方式nickstips.wordpress.com/2010/09/30/...
sudhAnsu63

40
order by case when MyDate is null then 1 else 0 end是很长的说法ORDER BY MyDate IS NULL
马丁

5
@Martin注意此问题未标记为mysql。我提供了一个通用的解决方案-在不同的数据库之间有许多不同的方式来做相同的事情。
RedFilter

1
@KyleDelaney因为order by 0被解释为列索引,并且列索引基于1。要按第三列对查询进行排序,您可以说order by 3(对于生产查询来说这是一个糟糕的主意),但是*在进行实验时非常方便(按原样)。
RedFilter

159

(一个“位”晚了,但是根本没有提到)

您未指定DBMS。

您可以在标准SQL(以及大多数现代DBMS(例如Oracle,PostgreSQL,DB2,Firebird,Apache Derby,HSQLDB和H2)中)指定NULLS LASTNULLS FIRST

用于NULLS LAST将它们排序到最后:

select *
from some_table
order by some_column DESC NULLS LAST

16
据我所知NULLS FIRST,并NULLS LAST已在SQL添加了:2003,但没有可利用的在不同DMBS”标准执行。根据数据库引擎的不同,请使用ORDER BY expr some_column DESC NULLS LAST(Oracle),ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL)或ORDER BY ISNULL(some_column), some_column ASC(具有不同ISNULL()实现的MySQL)。
SaschaM78 2013年

3
@ SaschaM78:NULL的默认排序取决于DBMS。有些在末尾排序,有些在开始。有些人不关心ASC/ DESC,而有些人则不使用null。因此,为了确保这一点的唯一方法,就是使用NULL FIRST/LAST ,如果在DBMS支持它。它记录了您的意图。使用isnull()或其他功能可以解决缺少的支持NULLS FIRST/LAST(由Oracle,PostgreSQL,DB2,Firebird,Apache Derby,HSQLDB和H2支持)
a_horse_with_no_name 2013年

完全正确,我只是想补充一个事实,就是有很多DBMS尚未遵循标准(尚未使用)或具有其特殊性,例如Oracle expr在使用NULLS FIRST / LAST时需要关键字。还要感谢第一个/最后一个显示的空值随数据库类型的不同而变化,这不知道!
SaschaM78

2
这看起来很有希望,但是可悲的是,我尝试了一下,但是NULLS LAST在我的MySQL数据库中无法正常工作。
AdmiralThrawn

1
@AdmiralAdama:您随时可以升级到Postgres
a_horse_with_no_name


14
order by coalesce(date-time-field,large date in future)

10
虽然这通常会起作用,但应注意,此答案有几个问题:将来的大日期可能会与实际数据发生冲突或少于实际数据,从而导致排序不完善。同样,这是一个“不可思议的数字”解决方案,没有自我记录。
RedFilter

当您需要将有问题的列与另一个日期列进行比较时,这恰好是@RedFilter答案的绝佳选择。我将此用于工会资历列表。如果员工具有合格日期(可以为空),则该日期会冒泡记录到顶部,否则请使用HireDate。使用ORDER BY ISNULL(QualifiedDate,'1-1-2099'),HireDate,LastName等可以使Qualified日期与HiredDate日期不冲突,并生成正确的年龄列表。
艾伦·费舍尔

14

您可以使用内置函数来检查null或不为null,如下所示。我对其进行了测试,并且工作正常。

select MyDate from MyTable order by ISNULL(MyDate,1) DESC, MyDate ASC;


对于使用mssql的日期,我发现将将来的日期放在ISNULL函数中很有用,即ISNULL(MyDate,'2100-01-01')
Emi-C

在MySQL中,它表示我传递了太多参数。我通过执行此操作来解析ISNULL(MyDate) DESC, MyDate ASC它,但是它的排序顺序不正确。
AdmiralThrawn

12

如果您的引擎允许ORDER BY x IS NULL, xORDER BY x NULLS LAST使用。但是,如果不是这样,这些方法可能会有所帮助:

如果按数字类型排序,则可以执行以下操作:(从另一个答案借用架构。)

SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId*0,1), DepartmentId;

结果显示按DepartmentId排序,最后为null

任何非空数都将变为0,而空值将变为1,这将最后对空值进行排序。

您还可以对字符串执行此操作:

SELECT *
FROM Employees
ORDER BY ISNULL(LEFT(LastName,0),'a'), LastName

结果显示按LastName排序,其中null为last

因为'a'> ''

这甚至可以通过强制为可为null的int并将上述方法用于int来处理日期:

SELECT *
FROM Employees
ORDER BY ISNULL(CONVERT(INT, HireDate)*0, 1), HireDate

(假设该模式具有HireDate。)

这些方法避免了必须提出或管理每种类型的“最大值”值或在数据类型(和最大值)发生变化时修复查询的问题(这是其他ISNULL解决方案所遇到的问题)。另外,它们比CASE短得多。


很棒!谢谢
瓦尼



3

感谢RedFilter为解决可为null的datetime字段排序的问题提供了出色的解决方案。

我正在为我的项目使用SQL Server数据库。

将datetime null值更改为'1'确实解决了datetime数据类型列的排序问题。但是,如果我们具有非datetime数据类型的列,则它将无法处理。

为了处理varchar列排序,我尝试使用'ZZZZZZZ',因为我知道该列没有以'Z'开头的值。它按预期工作。

在同一行上,我使用int和其他数据类型的最大值+1来按预期进行排序。这也给了我所需的结果。

但是,总是希望在数据库引擎本身中获得一些更简单的功能,例如:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

如a_horse_with_no_name提供的答案中所述。



3

如果您使用的是MariaDB,他们会在NULL值文档中提到以下内容

定购

当您按可能包含NULL值的字段排序时,所有NULL都被视为具有最低值。因此,按DESC顺序排序将看到NULL出现在最后。要强制将NULL视为最高值,可以在主字段为NULL时添加另一列,该列的值更高。例:

SELECT col1 FROM tab ORDER BY ISNULL(col1), col1;

降序,第一个为NULL:

SELECT col1 FROM tab ORDER BY IF(col1 IS NULL, 0, 1), col1 DESC;

就DISTINCT和GROUP BY子句而言,所有NULL值也被视为等效。

上面显示了两种按NULL值排序的方法,您也可以将它们与ASC和DESC关键字结合使用。例如,另一种首先获取NULL值的方法是:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^

2

使用“ case”的解决方案是通用的,但是不要使用索引。

order by case when MyDate is null then 1 else 0 end, MyDate

就我而言,我需要表现。

 SELECT smoneCol1,someCol2  
 FROM someSch.someTab
 WHERE someCol2 = 2101 and ( someCol1 IS NULL ) 
  UNION   
 SELECT smoneCol1,someCol2
 FROM someSch.someTab
 WHERE someCol2 = 2101 and (  someCol1 IS NOT NULL)  

1
如果您对性能感兴趣,则应该使用UNION ALL
RedFilter 2015年


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.