2017-02-21 51 views
3

我正在尋找一些T-SQL代碼,應該選擇「從當前日期返回的一年(同一時間是在一月份的上個星期天)」 。從SQL Server自動接收日期 - T-SQL

例如:

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

解析和處理日期爲字符串一般是令人難以接受的,我收集你沒有寫那表情。如果你想要一年前的日期,只需用'dateadd(year,-1,getdate()'替換每一個'getdate()'。 – shawnt00

回答

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) 
0

對這個問題的最好的事情是數字和日期表。 This answer shows you how to create one。這種表是在許多情況下很帥氣......

如果我理解正確的這個,你想要的最後一個星期日在去年一月在所有情況下?試試這個:

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到您的計算...

+0

你的困惑是基於OP定義「year」爲_starting_ on因此,2017-01-05在2016年的OP年,而不是2017年。同樣,2018-01-19在2017年的OP年,而不是2018年。在這兩種情況下,結果年都需要反過來其餘的日期是在1月的第一個星期日之後,格里曆和OP年恰好匹配。 – HABO

0

這是一個沒有日期表的方法(這仍然是一個好主意BTW)。對所有輸入進行測試,每次輸出正確的輸出。顯然你會重構這一點,因爲它是longwinded,只是爲了顯示每一步。

/* 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]; 
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;