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 end
说ORDER 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 LAST
或 NULLS FIRST
:
使用NULLS LAST
将它们排序到最后:
select *
from some_table
order by some_column DESC NULLS LAST
【讨论】:
AFAIKNULLS 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
(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 NULL
和 IS NOT NULL
在我的 MySQL 数据库中不起作用。【参考方案4】:
如果您的引擎允许 ORDER BY x IS NULL, x
或 ORDER 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 FIRST
或NULLS 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如何在升序排序时使空值排在最后的主要内容,如果未能解决你的问题,请参考以下文章