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

Posted

技术标签:

【中文标题】SQL如何在升序排序时使空值排在最后【英文标题】:SQL how to make null values come last when sorting ascending 【发布时间】:2010-12-02 16:31:53 【问题描述】:

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

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

【问题讨论】:

***.com/questions/151195/…的完全重复 另见***.com/questions/15121093/…和code.djangoproject.com/ticket/13312 【参考方案1】:
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate

【讨论】:

但是请注意,如果您在排序列上放置一个索引以提高性能(*),那么这种方法会使查询计划变得有些复杂,并失去很多性能优势。 * - 索引提供了预排序的数据,因此避免了每次查询执行的排序。建议尽可能过滤掉 NULL 记录,以完全避免此问题。 这里也给出了很好的答案,所有可能的方法都有优点和缺点nickstips.wordpress.com/2010/09/30/… order by case when MyDate is null then 1 else 0 endORDER BY MyDate IS NULL 的方式真的很长 @Martin 注意这个问题没有被标记为 mysql。我提供了一个通用的解决方案 - 有许多不同的方法可以在不同的数据库中做同样的事情。 @KyleDelaney 因为order by 0 被解释为列索引,并且列索引是从 1 开始的。要按第 3 列对查询进行排序,您可以说 order by 3(这对于生产查询来说是个糟糕的主意),但在试验时非常方便(就像 * 一样)。【参考方案2】:

(“有点”晚了,但根本没有提到)

您没有指定您的 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

【讨论】:

AFAIK NULLS FIRSTNULLS 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(MySQL 具有不同的 ISNULL() 实现)。 @SaschaM78:NULL 的默认排序取决于 DBMS。有些在最后排序,有些在开头。有些人不关心 ASC/DESC 有一些空值。因此,确保这一点的唯一方法是使用NULL FIRST/LAST if DBMS 支持它。它记录您的意图。使用isnull() 或其他函数可以解决缺少对NULLS FIRST/LAST 的支持(Oracle、PostgreSQL、DB2、Firebird、Apache Derby、HSQLDB 和 H2 支持) 你说得完全正确,我只是想补充一个事实,即周围有相当多的 DBMS 不遵循标准(还)或者有他们的专长,比如 Oracle 在使用时需要 expr 关键字NULLS FIRST/LAST。并且感谢第一个/最后一个显示的空值因数据库类型而异,不知道! 这看起来很有希望,但遗憾的是,我试过了,NULLS LAST 在我的 MySQL 数据库中不起作用。 @AdmiralAdama:你可以随时升级到 Postgres【参考方案3】:

我也只是偶然发现了这一点,以下似乎对我有用,在 MySQL 和 PostgreSQL 上:

ORDER BY date IS NULL, date DESC

在https://***.com/a/7055259/496209找到

【讨论】:

这看起来很有希望,但遗憾的是,我试过了,IS NULLIS NOT NULL 在我的 MySQL 数据库中不起作用。【参考方案4】:

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

如果您按数字类型排序,您可以这样做:(从another answer 借用架构。)

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

任何非空数都变为0,空值变为1,因为0

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

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

任何非空字符串都变成'',空值变成'a',因为'''a',所以最后对空值进行排序。

这甚至可以通过强制转换为可为空的 int 并使用上面的 int 方法来处理日期:

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

(让我们假设架构有 HireDate。)

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

对于使用 mssql 的日期,我发现在 ISNULL 函数中放置一个遥远的未来日期很有用,即 ISNULL(MyDate,'2100-01-01') 在 MySQL 中,它说我传递了太多参数。我通过 ISNULL(MyDate) DESC, MyDate ASC 解析了这个,但它没有按正确的顺序排序。【参考方案6】:
order by coalesce(date-time-field,large date in future)

【讨论】:

虽然这通常会起作用,但应该注意这个答案有一些问题:未来的大日期可能会与实际数据发生冲突或小于实际数据,从而导致排序不完善。此外,它是一个不能自我记录的“幻数”解决方案。 当您需要将相关列与另一个日期列进行比较时,这恰好是 @RedFilter 答案的一个很好的替代方案。我将此用于工会资历列表。如果员工有一个合格的日期(可以为空),则该日期冒泡记录到顶部,否则使用 HireDate。使用 ORDER BY ISNULL(QualifiedDate,'1-1-2099') 、 HireDate 、LastName 等使 Qualified 日期与 HiredDate 日期不冲突,并生成正确的优先级列表。【参考方案7】:

当您的订单列是数字(如排名)时,您可以将其乘以 -1,然后按降序排列。它将保持您期望的顺序,但将 NULL 放在最后。

select *
from table
order by -rank desc

【讨论】:

正要评论这个。从***.com/a/8174026/1193304 学来的,很棒【参考方案8】:

如果您使用 MariaDB,他们会在 NULL Values documentation 中提及以下内容。

Ordering

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

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

降序,NULLs在前:

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

所有 NULL 值也被认为是等效的 DISTINCT 和 GROUP BY 子句。

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

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

【讨论】:

【参考方案9】:
SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId, 99999);

见this blog post。

【讨论】:

【参考方案10】:

在Oracle中,可以使用NULLS FIRSTNULLS LAST:指定NULL值应该在非NULL值之前/之后返回:

ORDER BY  column-Name | [ ASC | DESC ] | [ NULLS FIRST | NULLS LAST ] 

例如:

ORDER BY date DESC NULLS LAST

参考:http://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj13658.html

【讨论】:

【参考方案11】:

感谢 RedFilter 为可空日期时间字段排序的错误问题提供了出色的解决方案。

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

将 datetime 空值更改为“1”确实解决了 datetime 数据类型列的排序问题。但是,如果我们有除日期时间数据类型以外的列,则它无法处理。

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

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

但是,在数据库引擎本身中获得一些更简单的东西总是很理想的,它可以执行以下操作:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

正如 a_horse_with_no_name 提供的答案中所述。

【讨论】:

【参考方案12】:

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

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)  

【讨论】:

如果您对性能感兴趣,您应该使用UNION ALL【参考方案13】:

使用 NVL 功能

  select * from MyTable order by NVL(MyDate, to_date('1-1-1','DD-MM-YYYY'))

这里是the alternative of NVL in most famous DBMS

【讨论】:

【参考方案14】:
order by -cast([nativeDateModify] as bigint) desc

【讨论】:

以上是关于SQL如何在升序排序时使空值排在最后的主要内容,如果未能解决你的问题,请参考以下文章

字符串排序空值

SQL Server 排序的时候使 null 值排在最后

SQL Server 排序的时候使 null 值排在最后

order by 升序排序是null字段如何排在最后?

为啥在 PostgreSQL 查询中排序 DESC 时 NULL 值排在第一位?

Mysql常见注意事项小记