我正在寻找一些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
请帮助。
答案 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)