按所有日期排序,低于某个值,然后是高于所述值升序的所有日期

时间:2016-11-15 17:08:13

标签: sql sql-server tsql date

鉴于以下数据:

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;

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

4 个答案:

答案 0 :(得分:3)

如果您有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;

答案 1 :(得分: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

答案 2 :(得分:2)

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

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的情况下编写查询。

答案 3 :(得分:1)

试试这个......

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