繁体   English   中英

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

[英]Auto pickup dates from SQL Server - T-SQL

我正在寻找一些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

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

我有一些在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

请帮忙。

这个问题的最好的事情是数字和日期表。 这个答案向您展示了如何创建一个 在很多情况下,这样的桌子很帅......

如果我理解正确的话,你想要在所有情况下在去年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 ...

这是一种没有日期表的方法(这仍然是一个好主意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];

在没有条件的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;
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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM