2017-09-15 4 views
0

J'ai créé une fonction dans SQL pour renvoyer la date appropriée d'une semaine ISO à partir d'un format comme "15W53". Où la première partie avant le "W" est le numéro de l'année et la seconde moitié est le numéro de la semaine. La date renvoyée doit renvoyer le début de la semaine pour cette date. Par exemple, 15W53 devrait renvoyer 12-28-2015 et 16W01 devrait retourner 01-04-2016. Cependant si je cours ceci pour les exemples suivants j'obtiens, d'après ce que j'ai lu au sujet de la semaine d'OIN, des résultats incorrects. Ai-je créé la fonction de manière incorrecte pour analyser la date?Récupérer la date de la semaine ISO dans SQL

SET DATEFIRST 1; 
SELECT dbo.[GetDateFromISOweek]('15W52') AS Correct, '15W52' -- Returns: 2015-12-21 
SELECT dbo.[GetDateFromISOweek]('15W53') AS Correct, '15W53' -- Returns: 2015-12-28 
SELECT dbo.[GetDateFromISOweek]('16W01') AS Incorrect, '16W01'-- Returns: 2015-12-28 
SELECT dbo.[GetDateFromISOweek]('16W02') AS Incorrect, '16W02'-- Returns: 2016-01-04 
SELECT dbo.[GetDateFromISOweek]('16W03') AS Incorrect, '16W03'-- Returns: 2016-01-11 

Fonction:

CREATE FUNCTION [dbo].[GetDateFromISOweek] (@Input VARCHAR(10)) 
RETURNS DATETIME 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    DECLARE @YearNum CHAR(4) 
    DECLARE @WeekNum VARCHAR(2) 

    SET @YearNum = SUBSTRING(@Input,0,CHARINDEX('W',@Input,0)) 
    SET @WeekNum = SUBSTRING(@Input,CHARINDEX('W',@Input,0)+1,LEN(@Input)) 

    RETURN(DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-1), 7)); 
END; 
+1

Ma recommandation serait Chaque fois que vous avez besoin d'écrire une fonction pour calculer une date, vous devriez probablement envisager de créer une table de dimension de date. Cela rendra votre vie 1000% plus facile. https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/ – Shawn

+0

Hey Shawn, c'est une super idée! Merci pour le lien! – InvaderZim

Répondre

1

Modifier -1 dans votre déclaration pour calculer si la première semaine de l'année devrait être considérer le premier ou non (si avoir plus de 3 jours). Quelque chose comme ça

case when DATEDIFF (day , convert(datetime,'01/01/'+ @YearNum),@FirstDay)>=3 then 1 else 0 end 

Le code complet, y compris le premier dimanche, peut être améliorée, mais fonctionne ...

CREATE FUNCTION [dbo].[GetDateFromISOweek] (@Input VARCHAR(10)) 
RETURNS DATETIME 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    DECLARE @YearNum CHAR(4) 
    DECLARE @WeekNum VARCHAR(2) 
    declare @FirstDay datetime 

    SET @YearNum = cast(SUBSTRING(@Input,0,CHARINDEX('W',@Input,0)) as int)+2000 
    SET @WeekNum = SUBSTRING(@Input,CHARINDEX('W',@Input,0)+1,LEN(@Input)) 
    set @FirstDay=DATEADD(DAY, (@@DATEFIRST - DATEPART(WEEKDAY, DATEADD(YEAR, @YearNum - 1900, 0)) + (8 - @@DATEFIRST) * 2) % 7, DATEADD(YEAR, @YearNum - 1900, 0))-1 

    RETURN(DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-case when DATEDIFF (day , convert(datetime,'01/01/'+ @YearNum),@FirstDay)>=3 then 1 else 0 end), 7)); 
END; 
go 
SET DATEFIRST 1; 
SELECT dbo.[GetDateFromISOweek]('15W52'),'15W52' union 
SELECT dbo.[GetDateFromISOweek]('15W53'),'15W53' union 
SELECT dbo.[GetDateFromISOweek]('16W01'), '16W01' union 
SELECT dbo.[GetDateFromISOweek]('16W02'), '16W02' union 
SELECT dbo.[GetDateFromISOweek]('16W03'), '16W03' 

Le résultat sera

----------------------- ----- 
2015-12-21 00:00:00.000 15W52 
2015-12-28 00:00:00.000 15W53 
2016-01-04 00:00:00.000 16W01 
2016-01-11 00:00:00.000 16W02 
2016-01-18 00:00:00.000 16W03 
+0

Génial! Il fonctionne comme un charme! – InvaderZim