2009-03-03 6 views
40

In Microsoft SQL Server, ho un certo numero settimanaOttenere date da un numero della settimana in T-SQL

(from DATEPART(wk, datecol)) 

ma quello che mi piacerebbe fare è trasformare questo nuovo nel lasso data per quella settimana.

Ad esempio,

SELECT DATEPART(wk, GETDATE()) 

rendimenti 10. desidero derivare 3/1/2009 e 3/7/2009 da questo numero.

È possibile?

+1

Vedere anche: http: // stackoverflow.it/questions/1267126/how-do-get-the-week-start-date-and-week-end-date-from-week-number-in-sql –

risposta

31

risposta di Quassnoi funziona, ma tipo di ti lascia sul gancio per ripulire le date se sono date nel bel mezzo della giornata (il suo inizio di settimana si lascia un giorno in meno del necessario per essere se usi un orario a metà giornata - puoi testare usando GETDATE()).

Ho usato qualcosa di simile in passato:

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 vantaggio collaterale di questo è che utilizzando @@ DATEFIRST è possibile gestire non standard Settimana da giorni (il valore predefinito è Domenica, ma con SET @@ DATEFIRST è possibile modificare questo).

sembra folle che semplice manipolazione data in SQL Server deve essere questo arcano, ma ci si va ...

+0

Um, DATECOL è la colonna definita dall'utente in l'esempio. Il codice di Quassnoi si basa solo su "DATEPART (giorno della settimana," disponibile nel 2000. – alyssackwan

+0

Ah, buon punto. Ho modificato l'immagine. Io modificherò di conseguenza. – mwigdahl

+0

Dov'è la modifica senza usare DATECOL? Vedi la mia risposta – Brad

3
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7 
13

È possibile impostare @WeekNum e @YearNum a quello che volete - in questo esempio sono derivati dalla variabile @datecol, che è impostata su GETDATE() a scopo illustrativo. Una volta che avete quelli VALORI è possibile calcolare l'intervallo di date per una settimana utilizzando la seguente:

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

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

-- once you have the @WeekNum and @YearNum set, the following calculates the date range. 
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

Puoi spiegare che cosa sono 6 e 5 nel DATEDIFF? – Ben

+0

@BenAdler che esegue 'select cast (0 come datetime)' restituisce '1900-01-01 00: 00: 00.000', quindi 5 e 6 devono essere rispettivamente 5 e 6 giorni da gennaio 1, 1900. jan 7 è la prima domenica dell'anno 1900. il resto del calc è meglio mostrato che spiegato: 'select datediff (wk, 6, '1/1/2015');' restituisce 5999 settimane dal 1/7/1900 'seleziona datepart (wk, '6/23/2015'); 'restituisce 26 settimane dal 1/1/2015 ' seleziona dateadd (wk, 5999 + (26 - 1), 6); 'restituisce: 2015-06-21 00 : 00: 00.000, che è esattamente 6024 settimane dalla prima domenica del 1900, ergo anche una domenica – ZagNut

+0

Le ultime due righe dove esattamente ciò di cui avevamo bisogno! Ho cambiato solo il 5 e il 6 perché le settimane iniziano lunedì e finiscono la domenica qui. \t DATEADD (wk, DATEDIFF (wk, 6, '1/1 /' + CAST (pr.Jaar come nvarchar)) + (pr.Week-1), 7) AS StartOfWeek, \t DATEADD (wk, DATEDIFF (wk, 5, '1/1 /' + CAST (pr.Jaar as nvarchar)) + (pr.Week-1), 6) AS EndOfWeek – Rob

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

Questo dovrebbe funzionare indipendentemente @@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 
0
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 
3

Che ne dite di una funzione che salta alla settimana prima del numero di quella settimana e poi passa attraverso i prossimi giorni fino a quando il numero della settimana cambia (max 7 passi), restituendo la nuova data?

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 
+1

Grande! ma devo modificare set @ tmpdate = dateadd (wk, @ weekno-2, @ tmpdate) – sebacipo

+0

Sebacipo aveva ragione visto che il primo giorno della settimana 1 potrebbe essere a dicembre dell'anno precedente. Inoltre, la convalida non è corretta se l'ultimo giorno dell'anno è la settimana 1. Grazie per la condivisione però .... questo è perfetto, con qualche tweek – Ian

1
dateadd(
    dd, 
    datepart(wk, @Date)*7, 
    convert(smalldatetime, convert(char,year(max(@Date)))+convert(char, '-01-01')) 
)-1 
1

Qui avete solo per passare l'anno e numero della settimana.

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

Per rispondere alla tua domanda:

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

Se la vostra settimana inizia dal Lunedi (su 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 
0

Risposta:

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

Ho preso la soluzione di elindeblom e l'ho modificata: l'uso di stringhe (anche se eseguito per date) mi rende nervoso per i diversi formati di date usati in tutto il mondo. Questo evita questo problema.

Anche se non richiesto, Ho anche incluso il tempo per cui la settimana si conclude 1 secondo prima di mezzanotte:

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

Sì, so di essere ancora la fusione, ma da un certo numero. Mi sembra più sicuro.

Questo si traduce in:

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

Give it @year e @Week, tornare prima data di quella settimana.

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

Ho appena incorporato il SELECT con una dichiarazione CASE (per la mia situazione Lunedi segnato il primo giorno della settimana, e non volevo a che fare con il comando 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 
0

questo funziona per me:

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

non ho preso il tempo di testare ogni risposta qui, ma nulla sembra più semplice ed efficiente come questo:

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 
1

più voti risposta funziona bene tranne il 1 ° settimana e la settimana scorsa dell'anno. Quando datecol valore è '2009-01-01', il risultato sarà 01/03/2009 e 2008/12/28.

La mia soluzione:

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; 

Questo mostrerà 01/01/2009 e 01/03/2009 per la prima settimana, e la visualizzazione 03/01/2009 e 03/07/2009 per la decima settimana.

Penso che questo sarebbe esattamente quello che vuoi. Puoi sostituire le variabili con le loro espressioni come desideri.