Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Ottieni il primo giorno della settimana in SQL Server

Per rispondere al motivo per cui hai un lunedì e non una domenica:

Stai aggiungendo un numero di settimane alla data 0. Che cos'è la data 0? 01-01-1900. Qual era il giorno del 01-01-1900? Lunedi. Quindi nel tuo codice stai dicendo, quante settimane sono trascorse da lunedì 1 gennaio 1900? Chiamiamolo [n]. Ok, ora aggiungi [n] settimane a lunedì 1 gennaio 1900. Non dovresti sorprenderti che questo finisca per essere un lunedì. DATEADD non ha idea che tu voglia aggiungere settimane ma solo fino ad arrivare a una domenica, è solo aggiungere 7 giorni, quindi aggiungere altri 7 giorni, ... proprio come DATEDIFF riconosce solo i confini che sono stati attraversati. Ad esempio, entrambi restituiscono 1, anche se alcune persone si lamentano del fatto che dovrebbe esserci una logica ragionevole incorporata per arrotondare per eccesso o per difetto:

SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');

Per rispondere a come ottenere una domenica:

Se vuoi una domenica, scegli una data base che non sia un lunedì ma piuttosto una domenica. Ad esempio:

DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);

Questo non si interromperà se modifichi il tuo DATEFIRST impostazione (o il codice è in esecuzione per un utente con un'impostazione diversa), a condizione che si desideri comunque una domenica indipendentemente dall'impostazione corrente. Se vuoi che queste due risposte siano jive, allora dovresti usare una funzione che fa dipendono da DATEFIRST impostazione, ad es.

SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);

Quindi se cambi il tuo DATEFIRST impostando su lunedì, martedì, cosa hai, il comportamento cambierà. A seconda del comportamento che desideri, potresti utilizzare una di queste funzioni:

CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO

...o...

CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO

Ora hai molte alternative, ma quale funziona meglio? Sarei sorpreso se ci fossero differenze sostanziali, ma ho raccolto tutte le risposte fornite finora e le ho eseguite attraverso due serie di test:uno economico e uno costoso. Ho misurato le statistiche del client perché non vedo I/O o memoria che giocano un ruolo nelle prestazioni qui (sebbene possano entrare in gioco a seconda di come viene utilizzata la funzione). Nei miei test i risultati sono:

Query di assegnazione "economica":

Function - client processing time / wait time on server replies / total exec time
Gandarez     - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday    - 357/2158/2515 - 0:25.2
trailmax     - 364/2160/2524 - 0:25.2
Curt         - 424/2202/2626 - 0:26.3

Query di assegnazione "costosa":

Function - client processing time / wait time on server replies / total exec time
Curt         - 1003/134158/135054 - 2:15
Gandarez     -  957/142919/143876 - 2:24
me Sunday    -  932/166817/165885 - 2:47
me datefirst -  939/171698/172637 - 2:53
trailmax     -  958/173174/174132 - 2:54

Posso trasmettere i dettagli dei miei test se lo si desidera, fermandosi qui perché sta già diventando piuttosto prolisso. Sono rimasto un po' sorpreso di vedere che quello di Curt è risultato essere il più veloce nella fascia alta, dato il numero di calcoli e il codice in linea. Forse farò dei test più approfonditi e ne parlerò in un blog... se voi ragazzi non avete obiezioni al fatto che io pubblichi le vostre funzioni altrove.