自动提取日期来自SQL Server - T-SQL

时间:2017-02-21 22:13:55

标签: sql sql-server sql-server-2008 tsql date

我正在寻找一些T-SQL代码,它应该选择的日期是"从当前日期开始的一年(在1月份的最后一个星期日的同一时间)"。

例如:

Current day      expected result
2017-02-05       2016-01-31
2017-01-05       2015-01-25
2018-02-19       2017-01-29
2018-01-19       2016-01-31
2019-02-28       2018-01-28

请注意:年份从一月的最后一个星期日开始

我有一些在SQL Server 2014中使用的T-SQL代码:

select 
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120)

以上代码选择当前年份的日期(1月份的最后一个星期日)。但我希望T-SQL代码可以选择去年(上个星期日和1月份的日期)日期。

详细说明 - 我希望T-SQL代码从下表中生成预期结果

Current day      T-SQL code answer       expected result
2017-02-05       2017-01-29              2016-01-31
2017-01-05       2016-01-31              2015-01-25
2018-02-19       2018-01-28              2017-01-29
2018-01-19       2017-01-29              2016-01-31
2019-02-28       2019-01-27              2018-01-28

请帮助。

4 个答案:

答案 0 :(得分:0)

这个问题最好的是数字和日期表。 This answer shows you how to create one。在许多情况下,这样的桌子非常漂亮......

如果我理解正确的话,你想要在所有情况下在去年1月的最后一个星期天吗?试试这个:

DECLARE @dummy TABLE(ID INT IDENTITY,YourDate DATE);
INSERT INTO @dummy VALUES
('2017-02-05'),('2017-01-05'),('2018-02-19'),('2018-01-19'),('2019-02-28');

WITH Years AS
(
    SELECT * FROM (VALUES(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019),(2020)) AS t(Yr)
)
,LastSundays AS
(
    SELECT Yr AS TheYear
          ,DATEADD(DAY,(DATEPART(WEEKDAY,LastOfJanuary) % 7)*(-1),LastOfJanuary) AS LastSundayOfJanuary
    FROM Years
    CROSS APPLY(SELECT CAST(CAST(Yr AS VARCHAR(4)) + '0131' AS DATE)) AS t(LastOfJanuary)
)
SELECT * 
FROM @dummy AS d
INNER JOIN LastSundays AS ls ON YEAR(DATEADD(YEAR,-1,d.YourDate))=ls.TheYear;

结果(我完全不理解第2行和第4行......

ID  YourDate    TheYear LastSundayOfJanuary
1   2017-02-05  2016    2016-01-31
2   2017-01-05  2016    2016-01-31 <--Your sample data is different...
3   2018-02-19  2017    2017-01-29
4   2018-01-19  2017    2017-01-29 <--Your sample data is different...
5   2019-02-28  2018    2018-01-28

提示您可能需要在计算中引入@@DATEFIRST ...

答案 1 :(得分:0)

这是一种没有日期表的方法(这仍然是一个好主意BTW)。测试所有输入,每次都输出正确的输出。很明显,你会稍微重构一下,因为它很长,只是为了显示每一步。

/* The input date. */

DECLARE
   @input DATE = '2019-02-28';

/* The input date less one year. */

DECLARE
   @date_minus_one_year DATE = DATEADD(yy,-1,@input);

/* The year part of the input date less one year. */

DECLARE
   @year_date_part INT = DATEPART(yy,@date_minus_one_year);

/* 31 Jan of the previous year. */

DECLARE
   @prev_year_jan_eom DATE = CAST(CAST(@year_date_part AS VARCHAR(4))+'-01-31' AS DATE);

/* What day of the week is 31 Jan of the previous year? */

DECLARE
   @previous_eom_dw_part INT = DATEPART(dw,@prev_year_jan_eom);

/* Offest 31 Jan to the previous Sunday, won't change if the 31st is itself a Sunday. */

DECLARE
   @output DATE = DATEADD(dd,1 - @previous_eom_dw_part,@prev_year_jan_eom);

/* Input and output */

SELECT
   @input input
  ,@output [output];

答案 2 :(得分:0)

如果没有case中的条件,我没想办法。它还使用将数字年份值转换为1月1日日期的技巧。

select case
  when
    datepart(dayofyear, dt) >
        31 - datepart(weekday, dateadd(day, 30, cast(year(dt) as varchar(4))))
  then
    dateadd(day,
        31 - datepart(weekday, dateadd(day, 30, cast(year(dt) as varchar(4)))),
        cast(year(dt) as varchar(4))
    )
  else
    dateadd(day,
        31 - datepart(weekday, dateadd(day, 30, cast(year(dt) - 1 as varchar(4)))),
        cast(year(dt) - 1 as varchar(4))
    )
end
from (values
    ('20100201'), ('20110301'), ('20120401'),
    ('20130501'), ('20140601'), ('20150701'),
    ('20160801'), ('20170901'), ('20181001')
) t(dt)

只是为了好玩(未经测试)

select
    dateadd(week,
        -52 * ceil(sign(datediff(day, dt, hs)) + 0.5),
        js
    )
from
    (select <date> dt) as t
    cross apply
    (
    select 31 - datepart(weekday,
         datefromparts(year(dt), 1, 31) as js
     ) t2;

答案 3 :(得分:0)

SELECT
  convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120)