SQL Server Order By isnull 意外结果

标签 sql sql-server

我正在尝试将一些 SQL 移植到代码中,我注意到 SQL Server 的 ORDER BY(和分区 ORDER BY)在某些情况下似乎表现得有些不确定,但也许我只是没有看到模式.我正在使用 Azure SQL 数据库,它应该或多或少是 SQL Server 2017,但有一些限制。

这里有一些例子:

select * from (
    values
        ('2014-01-01', NULL),
        ('2014-01-02', NULL),
        (NULL, '2014-01-01 00:01:00'),
        (NULL, '2014-01-01 23:59:59')
) AS temp (t, u)
order by isnull(t, u);

生成以下意外结果集,其中日期时间早于同一天的日期,并且晚日期时间早于早日期时间:

t           u
NULL        2014-01-01 23:59:59
NULL        2014-01-01 00:01:00
2014-01-01  NULL
2014-01-02  NULL

但是,如果我添加一些额外的行:

select * from (
    values
        ('2014-01-01', NULL),
        ('2014-01-02', NULL),
        (NULL, '2014-01-01 00:01:00'),
        (NULL, '2014-01-01 23:59:59'),
        (NULL, '2014-01-01 00:00:00'),
        (NULL, '2014-01-02 00:00:00')
) AS temp (t, u)
order by isnull(t, u);

日期仍然在日期时间之后,但现在日期时间是有序的:

t           u
NULL        2014-01-01 00:00:00
NULL        2014-01-01 00:01:00
NULL        2014-01-01 23:59:59
2014-01-01  NULL
NULL        2014-01-02 00:00:00
2014-01-02  NULL

使用分区产生类似的结果:

select 
    *,row_number() over (
    partition BY g
    ORDER BY isnull(t, u)
    ) rn
from (
    values
        (123, '2014-01-01', NULL),
        (123, '2014-01-02', NULL),
        (123, NULL, '2014-01-01 00:01:00'),
        (123, NULL, '2014-01-01 23:59:59')
) AS temp (g, t, u);


select 
    *,row_number() over (
    partition BY g
    ORDER BY isnull(t, u)
    ) rn
from (
    values
        (123, '2014-01-01', NULL),
        (123, '2014-01-02', NULL),
        (123, NULL, '2014-01-01 00:01:00'),
        (123, NULL, '2014-01-01 23:59:59'),
        (123, NULL, '2014-01-01 00:00:00'),
        (123, NULL, '2014-01-02 00:00:00')
) AS temp (g, t, u);

任何有关正在发生的事情或我如何重现此行为的指导都将不胜感激。

最佳答案

如果您运行此查询:

select temp.*, isnull(t, u)    from (values
        ('2014-01-01', NULL),
        ('2014-01-02', NULL),
        (NULL, '2014-01-01 00:01:00'),
        (NULL, '2014-01-01 23:59:59'),
        (NULL, '2014-01-01 00:00:00'),
        (NULL, '2014-01-02 00:00:00')
     ) temp (t, u)
order by isnull(t, u)

你会看到会发生什么。仅显示前 10 个字符。你可以在 this rex tester 中看到这个.

isnull() 必须确定表达式的类型。它选择一个字符串,其长度是第一个参数。因此,结果非常有意义。这在 documentation 中有解释。 :

Returns the same type as check_expression.

请注意,ANSI 标准 coalesce() 在类型检查方面做了更多工作,因此它会返回您期望的结果。

关于SQL Server Order By isnull 意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51736669/

相关文章:

sql - 获取列中值的最大计数

c# - 必须声明标量变量 "@UserName"

php - INSERT ..从多个表中选择多行

c# - 重写 LINQ 表达式查询以启用缓存 SQL 执行计划

sql-server - 在 SQL Server 中生成带有 4 个字母和 4 个数字的 8 位 varchar

sql - HIVE 检查表 1 中的数据,而表 2 中没有

mysql - 再次出现行时间差异

基于 ID 匹配从一个表到另一个表的 SQL 更新

sql - 满足条件的 COUNT 行(在具有特定条件的行处重置)

sql-server - 设置ODBC Hortonworks后在SQL中添加HIVE链接服务器