【问题标题】:SQL Server ORDER BY date and nulls lastSQL Server ORDER BY 日期和空值最后
【发布时间】:2011-08-18 17:09:39
【问题描述】:

我正在尝试按日期订购。我希望最近的日期最先出现。这很简单,但是有许多为空的记录,并且这些记录位于任何有日期的记录之前。

我尝试了一些没有成功的事情:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

ORDER BY coalesce(Next_Contact_Date, 99/99/9999)

如何按日期排序并让空值排​​在最后?数据类型为smalldatetime

【问题讨论】:

  • 排序顺序是否需要升序,但最后有空值?你的表中会有未来的日期吗?
  • @AllenG,是的,从过去到未来,以过去为先,依此类推。所以,是的,上升。是的,未来的日期是他们中的大多数。

标签: sql-server sql-server-2005 tsql


【解决方案1】:

smalldatetime 的范围截至 2079 年 6 月 6 日,因此您可以使用

ORDER BY ISNULL(Next_Contact_Date, '2079-06-05T23:59:00')

如果没有合法记录会有那个日期。

如果这不是您喜欢依赖更强大选项的假设,那就是对两列进行排序。

ORDER BY CASE WHEN Next_Contact_Date IS NULL THEN 1 ELSE 0 END, Next_Contact_Date

以上两个建议都不能使用索引来避免排序并给出相似的外观计划。

如果存在这样的索引,另一种可能性是

SELECT 1 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NOT NULL
UNION ALL
SELECT 2 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NULL
ORDER BY Grp, Next_Contact_Date

【讨论】:

  • 这个技巧也可以应用于VARCHAR字段(例如ORDER BY ISNULL(my_varchar, 'ZZZZZZ'))并且非常有用,特别是在使用GROUP BY . . . GROUPING SETS时以某种方式获取订单。感谢您发布此内容。
  • 为什么我们不能使用 order by desc 将空值放在底部?另外,为什么我们将 null 映射到 1 ?
【解决方案2】:

T-SQL Fundamentals for MS SQL Server 2012 一书的作者 Itzik Ben-Gan 说,“默认情况下,SQL Server 排序 NULL 标记在非NULL 值之前。要使 NULL 标记排在最后,您可以使用 >CASE 表达式,当“Next_Contact_Date 列为 NULL, "当它不是 NULL 时为 0。非 NULL 标记从表达式中取回 0 ; 因此,它们在 NULL 标记(得到 1)之前排序。这个 CASE 表达式用作第一个排序列。” Next_Contact_Date 列“应指定为第二个排序列。这样,非NULL 标记排序正确在他们中间。”这是您的 MS SQL Server 2012(和 SQL Server 2014)示例的解决方案查询:

ORDER BY 
   CASE 
        WHEN Next_Contact_Date IS NULL THEN 1
        ELSE 0
   END, Next_Contact_Date;

使用 IIF 语法的等效代码:

ORDER BY 
   IIF(Next_Contact_Date IS NULL, 1, 0),
   Next_Contact_Date;

【讨论】:

  • 另外,添加到答案中,如果您在空值周围切换 IIF 的 1 和 0 将转到顶部。如果您想通过将元组放在表的顶部来单出元组,这也适用。
【解决方案3】:
order by -cast([Next_Contact_Date] as bigint) desc

【讨论】:

  • 如果Next_Contact_Date为空Explicit conversion from data type date to bigint is not allowed.则抛出错误
【解决方案4】:

如果您的 SQL 不支持 NULLS FIRSTNULLS LAST,最简单的方法是使用 value IS NULL 表达式:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

将空值放在最后(NULLS LAST)或

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

将空值放在前面。这不需要知道列的类型,并且比CASE 表达式更易于阅读。

编辑:唉,虽然这适用于 PostgreSQL 和 MySQL 等其他 SQL 实现,但它不适用于 MS SQL Server。我没有要测试的 SQL Server,我依赖 Microsoft 的文档和测试其他 SQL 实现。根据微软的说法,value IS NULLis an expression 应该像任何其他表达式一样可用。和 ORDER BY is supposed to take expressions 就像任何其他接受表达式的语句一样。但它实际上不起作用。

因此,SQL Server 的最佳解决方案似乎是 CASE 表达式。

【讨论】:

  • 这不是有效的 SQL Server 语法
  • 很抱歉。它应该在 Microsoft 文档中是有效的,并且可以在其他 SQL 中使用,但 MS 实际上不允许这样做。
  • 性能方面,这听起来很糟糕,您正在执行 2 个排序标准
  • 在您链接的 Microsoft 文档中,我读到 value IS NULL 不是 表达式,而是 谓词 .不一样。
  • 根据微软的说法,谓词是一个表达式。这实际上是docs.microsoft.com/en-us/sql/t-sql/queries/predicates的前三个词
【解决方案5】:

有点晚了,但也许有人觉得它有用。

对我来说,由于表扫描,ISNULL 是不可能的。 UNION ALL 需要我重复一个复杂的查询,而且由于我只选择了 TOP X,所以效率不会很高。

如果您能够更改表格设计,您可以:

  1. 添加另一个字段,仅用于排序,例如 Next_Contact_Date_Sort。

  2. 根据您的需要,创建一个用大(或小)值填充该字段的触发器:

    CREATE TRIGGER FILL_SORTABLE_DATE ON YOUR_TABLE AFTER INSERT,UPDATE AS 
    BEGIN
        SET NOCOUNT ON;
        IF (update(Next_Contact_Date)) BEGIN
        UPDATE YOUR_TABLE SET Next_Contact_Date_Sort=IIF(YOUR_TABLE.Next_Contact_Date IS NULL, 99/99/9999, YOUR_TABLE.Next_Contact_Date_Sort) FROM inserted i WHERE YOUR_TABLE.key1=i.key1 AND YOUR_TABLE.key2=i.key2
        END
    END
    

【讨论】:

    【解决方案6】:

    如有必要,请使用 desc 并乘以 -1。最后使用 null 的 int 升序排序示例:

    select * 
    from
    (select null v union all select 1 v union all select 2 v) t
    order by -t.v desc
    

    【讨论】:

    • 不要认为这适用于日期等变量..
    【解决方案7】:

    我知道这很旧,但这对我有用

    Order by Isnull(Date,'12/31/9999')
    

    【讨论】:

      【解决方案8】:

      我想我最终找到了一种显示空值并且仍然能够使用索引进行排序的方法。

      这个想法非常简单——创建一个基于现有列的可计算列,并在其上放置一个索引。

      ALTER TABLE dbo.Users 
      ADD [FirstNameNullLast]  
      AS (case when [FirstName] IS NOT NULL AND (ltrim(rtrim([FirstName]))<>N'' OR [FirstName] IS NULL) then [FirstName] else N'ZZZZZZZZZZ' end) PERSISTED
      

      因此,我们在 SQL 中创建了一个持久的可计算列,在该列中,所有空白和空值都将替换为“ZZZZZZZZ”,这意味着,如果我们尝试基于该列进行排序,我们将最后查看所有空值或空白值。 现在我们可以在我们的新索引中使用它了。

      像这样:

      CREATE NONCLUSTERED INDEX [IX_Users_FirstNameNullLast] ON [dbo].[Users]
      (
          [FirstNameNullLast] ASC
      )
      

      所以,这是一个普通的非聚集索引。我们可以随心所欲地更改它,即包括额外的列、增加索引列的数量、更改排序顺序等。

      【讨论】:

        【解决方案9】:

        我知道这是一个旧线程,但在 SQL Server 中,空值总是低于非空值。所以只需要按 Desc 排序

        在你的情况下Order by Next_Contact_Date Desc 应该足够了。

        来源:order by with nulls- LearnSql

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-05
          • 1970-01-01
          • 2021-12-23
          • 1970-01-01
          • 2017-08-22
          • 2023-02-21
          • 1970-01-01
          相关资源
          最近更新 更多