web-dev-qa-db-fra.com

Obtenir les dates d'un numéro de semaine dans T-SQL

Dans Microsoft SQL Server, j'ai un numéro de semaine 

(from DATEPART(wk, datecol)) 

mais ce que je voudrais faire, c’est de remettre cela dans la période de cette semaine.

Par exemple, 

SELECT DATEPART(wk, GETDATE())

rendements 10. Je voudrais tirer 3/1/2009 et 3/7/2009 de ce nombre.

Est-ce possible?

43
Jason

La réponse de Quassnoi fonctionne, mais vous laisse en quelque sorte sur le crochet pour nettoyer les dates si elles sont au milieu de la journée (son début de semaine vous laisse un jour plus tôt que vous n'auriez dû si vous utilisez un temps au milieu du jour - vous pouvez tester en utilisant GETDATE ()).

J'ai utilisé quelque chose comme ça dans le passé:

SELECT 
   CONVERT(varchar(50), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, DATECOL), DATECOL)), 101),
   CONVERT(varchar(50), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, DATECOL) - 6, DATECOL)), 101)

Un des avantages de cela est qu’en utilisant @@ DATEFIRST, vous pouvez gérer les jours de début de semaine non standard (la valeur par défaut est dimanche, mais avec SET @@ DATEFIRST, vous pouvez le modifier).

Il semble fou que la simple manipulation de date dans SQL Server doive être aussi arcanique, mais voilà ...

31
mwigdahl

Vous pouvez définir @WeekNum et @YearNum sur ce que vous voulez. Dans cet exemple, elles sont dérivées de la variable @datecol, qui est définie sur GETDATE () à des fins d'illustration. Une fois que vous avez ces valeurs, vous pouvez calculer la plage de dates pour une semaine en utilisant les éléments suivants:

 DECLARE @datecol datetime = GETDATE (); 
 DECLARE @WeekNum INT 
 , @YearNum char (4); 

 SELECT @WeekNum = DATEPART (WK, @datecol) 
 , @YearNum = CAST (DATEPART (YY, @datecol) AS CHAR (4)); 

-- une fois que vous avez défini les paramètres @WeekNum et @YearNum, voici ce qui calcule la plage de dates .
 SELECT DATEADD (semaine, DATEDIFF (semaine, 6, '1/1 /' + @YearNum) + (@ WeekNum-1), 6) AS StartOfWeek; 
 SÉLECTIONNER DATEADD (semaine, DATEDIFF (semaine, 5, '1/1/'+ @YearNum) + (@ WeekNum-1), 5) AS EndOfWeek;
16
elindeblom

Pour répondre à ta question:

--CHANGE A WEEK NUMBER BACK INTO A DATE FOR THE FIRST DATE OF THE WEEK
DECLARE @TaskWeek INT = 17
DECLARE @TaskYear INT = 2013

SELECT DATEADD(WEEK, @TaskWeek - 1,DATEADD(dd, 1 - DATEPART(dw, '1/1/' + CONVERT(VARCHAR(4),@TaskYear)), '1/1/' + CONVERT(VARCHAR(4),@TaskYear)))
4
Brad

Si votre semaine commence à partir de lundi (sur SQL Server 2008)

select datecol,
  DATEPART(ISOWK, datecol) as week,
  ((DATEPART(dw, datecol)+5)%7)+1 as weekday,
  (DATEADD(dd, -((DATEPART(dw, datecol)+5)%7), datecol)) as Monday,
  (DATEADD(dd, -((DATEPART(dw, datecol)+5)%7)+6, datecol)) as Sunday
4
SeeR
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7
3
Quassnoi

Que diriez-vous d’une fonction qui saute à la semaine qui précède le numéro de la semaine puis parcourt les prochains jours jusqu’à ce que le numéro de la semaine change (7 étapes au maximum) et renvoie la nouvelle date?

CREATE FUNCTION dbo.fnGetDateFromWeekNo
(@weekNo int , @yearNo  int)
RETURNS smalldatetime
AS
BEGIN 

DECLARE @tmpDate smalldatetime


set @tmpdate= cast(cast (@yearNo as varchar) + '-01-01' as smalldatetime)
-- jump forward x-1 weeks to save counting through the whole year 
set @tmpdate=dateadd(wk,@weekno-1,@tmpdate)

-- make sure weekno is not out of range
if @WeekNo <= datepart(wk,cast(cast (@yearNo as varchar) + '-12-31' as smalldatetime))
BEGIN
    WHILE (datepart(wk,@tmpdate)<@WeekNo)
    BEGIN
        set @tmpdate=dateadd(dd,1,@tmpdate)
    END
END
ELSE
BEGIN
    -- invalid weeknumber given
    set @tmpdate=null
END


RETURN @tmpDate

END
3
Marc Ozin

J'ai pris la solution d'elindeblom et je l'ai modifiée - l'utilisation de chaînes (même si elles sont converties en dates) me rend nerveuse pour les différents formats de dates utilisés dans le monde. Cela évite ce problème. 

Bien que non demandé, j'ai également inclus l'heure afin que la semaine se termine 1 seconde avant minuit:

    DECLARE @WeekNum INT = 12,
        @YearNum INT = 2014 ;

    SELECT  DATEADD(wk,
                    DATEDIFF(wk, 6,
                             CAST(RTRIM(@YearNum * 10000 + 1 * 100 + 1) AS DATETIME))
                    + ( @WeekNum - 1 ), 6) AS [start_of_week],
            DATEADD(second, -1,
                    DATEADD(day,
                            DATEDIFF(day, 0,
                                     DATEADD(wk,
                                             DATEDIFF(wk, 5,
                                                      CAST(RTRIM(@YearNum * 10000
                                                                 + 1 * 100 + 1) AS DATETIME))
                                             + ( @WeekNum + -1 ), 5)) + 1, 0)) AS [end_of_week] ;

Oui, je sais que je lance toujours mais à partir d'un nombre. C'est "plus sûr" pour moi.

Cela se traduit par:

    start_of_week           end_of_week
    ----------------------- -----------------------
    2014-03-16 00:00:00.000 2014-03-22 23:59:59.000
1
Paul Sturm

Cela devrait fonctionner indépendamment de @@DATEFIRST

ALTER FUNCTION dbo.DEV_VW_WeekSerial
    (@YearNum int,
    @WeekNum int,
    @DayNum int)
    RETURNS Date AS

    BEGIN

        DECLARE @FirstDayYear As Date;

        SET @FirstDayYear='01/01/' + CAST(@YearNum As varchar)

        RETURN dateadd(d,(@DayNum-datepart(weekday,@FirstDayYear)),dateadd(week, @WeekNum-1,@FirstDayYear))

    END
1
kunguito

Donnez-lui @Year et @Week, Renvoyez la première date de cette semaine.

Declare @Year   int
,@Week int
,@YearText varchar(4)

set @Year = 2009
set @Week = 10

set @YearText = @Year

print dateadd(day
             ,1 - datepart(dw, @YearText + '-01-01')
                + (@Week-1) * 7
             ,@YearText + '-01-01')
1
markmolamhoi

Je viens d'incorporer le SELECT à une instruction CASE (pour ma situation lundi marquait le premier jour de la semaine et ne voulait pas traiter de la commande SET DATEFIRST:

CASE DATEPART(dw,<YourDateTimeField>)
   WHEN 1 THEN CONVERT(char(10), DATEADD(DD, -6, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), <YourDateTimeField>,126)
   WHEN 2 THEN CONVERT(char(10), <YourDateTimeField>,126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 6, <YourDateTimeField>),126)
   WHEN 3 THEN CONVERT(char(10), DATEADD(DD, -1, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 5, <YourDateTimeField>),126)
   WHEN 4 THEN CONVERT(char(10), DATEADD(DD, -2, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 4, <YourDateTimeField>),126)
   WHEN 5 THEN CONVERT(char(10), DATEADD(DD, -3, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 3, <YourDateTimeField>),126)
   WHEN 6 THEN CONVERT(char(10), DATEADD(DD, -4, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 2, <YourDateTimeField>),126)
   WHEN 7 THEN CONVERT(char(10), DATEADD(DD, -5, <YourDateTimeField>),126) +  ' to ' + CONVERT(char(10), DATEADD(DD, 1, <YourDateTimeField>),126)
   ELSE 'UNK'
END AS Week_Range
1
Brian Dorris
dateadd(
  dd, 
  datepart(wk, @Date)*7, 
  convert(smalldatetime, convert(char,year(max(@Date)))+convert(char, '-01-01'))
)-1 
1
Charlie

La plupart des votes répondent, sauf la 1re semaine et la semaine dernière de l'année. Lorsque datecol est défini sur '2009-01-01' , le résultat est 01/03/2009 et 12/28/2008 .

Ma solution:

DECLARE @Date date = '2009-03-01', @WeekNum int, @StartDate date;
SELECT @WeekNum = DATEPART(WEEK, @Date);
SELECT @StartDate = DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0));
SELECT CONVERT(nvarchar, CASE WHEN @WeekNum = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0) AS date) ELSE DATEADD(DAY, 7 * @WeekNum, @StartDate) END, 101) AS StartOfWeek
      ,CONVERT(nvarchar, CASE WHEN @WeekNum = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date) + 1, 0)) ELSE DATEADD(DAY, 7 * @WeekNum + 6, @StartDate) END, 101) AS EndOfWeek;

Ceci affichera 01/01/2009 et 01/03/2009 pour la 1ère semaine, et affichera 03/01/2009 et 03/07/2009 pour le 10ème semaine.

Je pense que ce serait ce que vous voulez exactement. Vous pouvez remplacer les variables par leurs expressions à votre guise.

1
Leo

Ici, il vous suffit de passer l'année et le numéro de semaine.

DECLARE @Year VARCHAR(4)

SET @Year= '2012'

DECLARE @FirstDate DATETIME

SET @FirstDate = (SELECT DATEADD(dd,1,(SELECT DATEADD(wk,DATEPART(wk,GETDATE())-1,Convert(DAteTime,'01-01-' + @Year))))
                 )
DECLARE @LastDate DATETIME

SET @LastDate =(SELECT DATEADD(dd,4,@FirstDate))

SELECT @FirstDate
       ,@LastDate
1
Ajay
DECLARE @dayval int,
 @monthval int,
 @yearval int

SET @dayval = 1
SET @monthval = 1
SET @yearval = 2011


DECLARE @dtDateSerial datetime

        SET @dtDateSerial = DATEADD(day, @dayval-1,
                                DATEADD(month, @monthval-1,
                                    DATEADD(year, @yearval-1900, 0)
                                )
                            )

DECLARE @weekno int
SET @weekno = 53


DECLARE @weekstart datetime
SET @weekstart = dateadd(day, 7 * (@weekno -1) - datepart (dw, @dtDateSerial), @dtDateSerial)

DECLARE @weekend datetime
SET @weekend = dateadd(day, 6, @weekstart)

SELECT @weekstart, @weekend
0
Stefan Steiger

Cela fonctionne pour moi:

select 
    convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 1, DATECOL), 101),
    convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 7, DATECOL), 101)
0
Tomas Chabada

déclarer @IntWeek en tant que varchar (20) SET @IntWeek = '201820'

SELECT DATEADD (semaine, date de date (semaine, @@ DATEFIRST, GAUCHE (@ IntWeek, 4) + '- 01-01')) + (cast ((DROITE (@ IntWeek, 2) en tant que int) -1), @@ DATEFIRST) StartOfWeek

0
FrankieMnemonic

Je n'ai pas pris le temps de tester toutes les réponses, mais rien ne semble aussi simple et efficace:

DECLARE @WeekNum int
DECLARE @YearNum char(4)

SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + @YearNum) + (@WeekNum-1), 6) AS StartOfWeek

SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + @YearNum) + (@WeekNum-1), 5) AS EndOfWeek
0
hurleystylee
SELECT DATEADD(week, @weekNumber - 1, DATEADD(DAY, @@datefirst - DATEPART(weekday, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01') - 6, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01'))
0
Brad

Réponse:

select  DateAdd(day,-DATEPart(DW,<Date>), <Date>) [FirstDayOfWeek] ,DateAdd(day,-DATEPart(DW,<Date>)+6, <Date>) [LastDayOfWeek]
FROM <TABLE>
0
user3403451