【问题标题】:Order by all dates below some value descending then by all dates above said value ascending按低于某个值的所有日期降序排序,然后按高于该值的所有日期升序排序
【发布时间】:2016-11-15 17:08:12
【问题描述】:

给定以下数据:

Effective Date
--------------
    2014-01-01
    2015-01-01
    2016-01-01
    2017-01-01
    2018-01-01

我想按相对于(例如)2016-06-01 的日期排序,其中所有低于2016-06-01 的降序值都位于高于2016-06-01 的所有升序值之前。

Relative to date: 2016-06-01 the desired ordering is

Effective Date
--------------
    2016-01-01
    2015-01-01
    2014-01-01
    2017-01-01
    2018-01-01

我想出的实现所需排序的最佳方法是:

CREATE TABLE #Dates
(
    EffectiveDate DATETIME2
);

DECLARE @CurrentDate DATETIME2 = '2016-06-01';
DECLARE @MinDate DATETIME2 = '0001-01-01';

INSERT INTO #Dates (EffectiveDate) VALUES ('2014-01-01');
INSERT INTO #Dates (EffectiveDate) VALUES ('2015-01-01');
INSERT INTO #Dates (EffectiveDate) VALUES ('2016-01-01');
INSERT INTO #Dates (EffectiveDate) VALUES ('2017-01-01');
INSERT INTO #Dates (EffectiveDate) VALUES ('2018-01-01');

SELECT
    *
FROM
    #Dates
ORDER BY
    CASE
        WHEN #Dates.EffectiveDate < @CurrentDate
            THEN DATEDIFF(DAY, #Dates.EffectiveDate, @CurrentDate)
        ELSE
            DATEDIFF(DAY, @CurrentDate, #Dates.EffectiveDate) - DATEDIFF(DAY, @CurrentDate, @MinDate)
    END;

DROP TABLE #Dates;

有没有更好的方法来实现所需的排序?

【问题讨论】:

    标签: sql sql-server tsql date


    【解决方案1】:

    如果您有 2012 年及以上版本。

    SELECT
        *
    FROM
        #Dates
    ORDER BY
        IIF(#Dates.EffectiveDate <= @CurrentDate, 0,1) ASC
        , ABS(DATEDIFF(day,#Dates.EffectiveDate, @CurrentDate)) ASC;
    

    如果你有 2008 年:

    SELECT
        *
    FROM
        #Dates
    ORDER BY
        CASE 
            WHEN #Dates.EffectiveDate <= @CurrentDate THEN  0
            ELSE 1 END ASC
        , ABS(DATEDIFF(day,#Dates.EffectiveDate, @CurrentDate)) ASC;
    

    【讨论】:

    • 添加了 2008 年的案例。
    • 只是好奇...为什么要使用 db 特定语言?案例仍然适用于两者。 iif 真的那么快吗?
    • IIF 是原始答案。在上面的 bjones 评论之后添加了 CASE。我怀疑它们的性能会相同,但 IIF 肯定更短。
    • IIF 只是语法糖,它在幕后转换为 CASE 表达式。
    【解决方案2】:

    这是一种不同的方法。让我知道这是否适合您的需求。我使用的是表变量而不是临时表。

    DECLARE @Dates TABLE
    (
     EffectiveDate DATETIME2
    );
    
    DECLARE @CurrentDate DATETIME2 = '2016-06-01';
    
    INSERT INTO @Dates (EffectiveDate) VALUES ('2014-01-01');
    INSERT INTO @Dates (EffectiveDate) VALUES ('2015-01-01');
    INSERT INTO @Dates (EffectiveDate) VALUES ('2016-01-01');
    INSERT INTO @Dates (EffectiveDate) VALUES ('2017-01-01');
    INSERT INTO @Dates (EffectiveDate) VALUES ('2018-01-01');
    
    SELECT *
    FROM (SELECT TOP 1000000 *
        FROM @Dates t1
        WHERE EffectiveDate <= @CurrentDate
        ORDER BY EffectiveDate DESC 
    UNION ALL
        SELECT TOP 1000000 *
        FROM @Dates t2
        WHERE EffectiveDate NOT IN (
                                SELECT *
                                FROM @Dates
                                WHERE EffectiveDate <= @CurrentDate
                                    )
        ORDER BY EffectiveDate
    ) t
    

    ******* 编辑 *******

    正如 HABO 所说,上述结果集不一定有保证的顺序。下面的编辑应该会解决这个问题。

    SELECT *
    FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY EffectiveDate DESC) Sort
          FROM @Dates t1
          WHERE EffectiveDate <= @CurrentDate
        UNION ALL
          SELECT *
             ,(SELECT MAX(Sort) 
                FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY EffectiveDate DESC) Sort
                        FROM @Dates t1
                        WHERE EffectiveDate <= @CurrentDate
                      ) t2
              ) 
             + ROW_NUMBER() OVER(ORDER BY EffectiveDate ASC) Sort
        FROM @Dates t3
        WHERE EffectiveDate NOT IN (SELECT *
                                    FROM @Dates
                                    WHERE EffectiveDate <= @CurrentDate)
    ) t
    ORDER BY t.Sort
    

    【讨论】:

    • 您在哪里订购结果?如果最终结果中没有 ORDER BY 子句,则无法保证订单。 UNION ALL 不保证保持秩序。 TOP 也不保证任何特定的顺序,只是这些行是基于指定的 ORDER BY 的子集。
    • @HABO,同意我忽略了这一点。因此,我很好奇如何使用相同的方法使其工作。它可能很难看,但似乎有效。
    【解决方案3】:

    对于这种特定情况,解决方案是直截了当的;将小于当前日期和大于当前日期拆分为两个单独的列并进行相应排序:

    WITH CTE AS (
        SELECT
            EffectiveDate,
            CASE WHEN EffectiveDate <= @CurrentDate THEN EffectiveDate END AS DL,
            CASE WHEN EffectiveDate >  @CurrentDate THEN EffectiveDate END AS DG
        FROM #Dates
    )
    SELECT * FROM CTE
    ORDER BY DL DESC, DG
    

    结果:

    EffectiveDate       | DL                  | DG
    ====================+=====================+====================
    2016-01-01 00:00:00 | 2016-01-01 00:00:00 | NULL
    2015-01-01 00:00:00 | 2015-01-01 00:00:00 | NULL
    2014-01-01 00:00:00 | 2014-01-01 00:00:00 | NULL
    2017-01-01 00:00:00 | NULL                | 2017-01-01 00:00:00
    2018-01-01 00:00:00 | NULL                | 2018-01-01 00:00:00
    

    请注意,可以在不使用 CTE 的情况下编写查询。

    【讨论】:

      【解决方案4】:

      试试这个...

      IF OBJECT_ID(N'tempdb..#Dates') IS NOT NULL
          DROP TABLE #Dates
      GO
      CREATE TABLE #Dates
      (
          EffectiveDate DATETIME2
      );
      
      DECLARE @CurrentDate DATETIME2 = '2016-06-01';
      DECLARE @MinDate DATETIME2 = '0001-01-01';
      
      INSERT INTO #Dates (EffectiveDate) VALUES ('2014-01-01');
      INSERT INTO #Dates (EffectiveDate) VALUES ('2015-01-01');
      INSERT INTO #Dates (EffectiveDate) VALUES ('2016-01-01');
      INSERT INTO #Dates (EffectiveDate) VALUES ('2017-01-01');
      INSERT INTO #Dates (EffectiveDate) VALUES ('2018-01-01');
      
      SELECT
          EffectiveDate
      FROM
      (
          SELECT
              CASE
                  WHEN EffectiveDate <= @CurrentDate THEN 1
                  ELSE 2
              END GroupId,
              CASE
                  WHEN EffectiveDate <= @CurrentDate THEN EffectiveDate
                  ELSE NULL
              END Group1,
              CASE
                  WHEN EffectiveDate <= @CurrentDate THEN NULL
                  ELSE EffectiveDate
              END Group2,
              EffectiveDate
          FROM
              #Dates
      )A
      ORDER BY
          GroupId,
          Group1 DESC,
          Group2 ASC
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-08
        • 2020-05-20
        • 1970-01-01
        • 2021-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多