Una cosa interessante su DATEDIFF()
funzione in SQL Server è che ignora il tuo SET DATEFIRST
valore.
Tuttavia, questo non è un bug. Documentazione Microsoft per DATEDIFF()
afferma chiaramente quanto segue:
Specificando SET DATEFIRST
non ha effetto su DATEDIFF
. DATEDIFF
utilizza sempre la domenica come primo giorno della settimana per garantire che la funzione operi in modo deterministico.
Nel caso non lo sapessi, SET DATEFIRST
imposta il primo giorno della settimana per la tua sessione. È un numero da 1 a 7 (che corrisponde a lunedì a domenica).
Il valore iniziale per SET DATEFIRST
è implicitamente impostato dall'impostazione della lingua (che puoi impostare con il SET LANGUAGE
dichiarazione). Il valore effettivo dipenderà dalla lingua impostata. Ad esempio il valore predefinito per us_english
la lingua è 7
(domenica), mentre il valore predefinito per il British
la lingua è 1
(Lunedi).
Tuttavia, puoi utilizzare un SET DATEFIRST
istruzione per ignorarlo in modo da poter continuare a utilizzare la stessa lingua mentre si utilizza un giorno diverso per il primo giorno della settimana.
Ma come accennato, il SET DATEFIRST
value non ha effetto su DATEDIFF()
funzione. Il DATEDIFF()
la funzione presuppone sempre che la domenica sia il primo giorno della settimana indipendentemente dal tuo SET DATEFIRST
valore.
Ciò può causare alcuni problemi interessanti quando si utilizza DATEDIFF()
se non sai come funziona.
Se ti trovi in questa situazione, si spera che gli esempi in questa pagina possano aiutarti.
Esempio 1 – Il problema
Innanzitutto, ecco un esempio del problema reale. Nota che possiamo recuperare il SET DATEFIRST
valore selezionando @@DATEFIRST
.
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET LANGUAGE us_english; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result'; SET LANGUAGE British; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
Risultato:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
In questo caso, la prima data cade di domenica e la seconda data di lunedì. Quindi normalmente ti aspetteresti il DATEDIFF()
britannico risultato per restituire 1
. Te lo aspetteresti perché il limite della parte settimanale viene superato quando va da domenica a lunedì (perché il SET DATEFIRST
il valore è 1
che significa "lunedì" e lunedì segna l'inizio di una nuova settimana).
Ma perché DATEDIFF()
ignora il tuo SET DATEFIRST
value e presuppone che la domenica sia l'inizio della settimana, otteniamo lo stesso risultato per entrambe le lingue.
Per sicurezza, eseguirò di nuovo la query, ma questa volta imposterò SET DATEFIRST
valore esplicitamente . In altre parole, invece di impostare la lingua, userò il SET DATEFIRST
dichiarazione:
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result'; SET DATEFIRST 1; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
Risultato:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
Stesso risultato, anche quando imposti esplicitamente SET DATEFIRST
valore. Questa non è una sorpresa però:sarei sorpreso se non lo facesse restituire lo stesso risultato.
Inoltre, questo conferma semplicemente che DATEDIFF()
funziona esattamente come previsto.
Quindi, come cambiarlo in modo che il nostro DATEDIFF()
i risultati rispettano il nostro SET DATEFIRST
valore?
La soluzione
Ecco una soluzione/soluzione alternativa che ti consentirà di ottenere i risultati desiderati. Ciò garantirà che il tuo SET DATEFIRST
le impostazioni vengono prese in considerazione nel tuo DATEDIFF()
risultati.
Tutto quello che devi fare è sottrarre @@DATEFIRST
dalle date di input.
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result'; SET DATEFIRST 1; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'British DATEDIFF() Result';
Risultato:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 1 | +-----------------------+-----------------------------+
Questo utilizza il DATEADD()
funzione per ridurre le date di input dell'importo di @@DATEFIRST
(che è il tuo SET DATEFIRST
valore).
In questo caso il DATEDIFF()
la funzione utilizza ancora la domenica come primo giorno della settimana, tuttavia le date effettive utilizzate nel calcolo sono diverse. Sono stati spostati indietro nel tempo della quantità di @@DATEFIRST
.
L'esempio seguente mostra le date utilizzate nel calcolo:
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date' UNION ALL SELECT @enddate, @@DATEFIRST, DATEADD(day, [email protected]@DATEFIRST, @enddate); SET DATEFIRST 1; SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date' UNION ALL SELECT @enddate, @@DATEFIRST, DATEADD(day, [email protected]@DATEFIRST, @enddate);
Risultato:
+-----------------+---------------+------------------+ | Original Date | Subtract By | Resulting Date | |-----------------+---------------+------------------| | 2025-01-05 | 7 | 2024-12-29 | | 2025-01-06 | 7 | 2024-12-30 | +-----------------+---------------+------------------+ +-----------------+---------------+------------------+ | Original Date | Subtract By | Resulting Date | |-----------------+---------------+------------------| | 2025-01-05 | 1 | 2025-01-04 | | 2025-01-06 | 1 | 2025-01-05 | +-----------------+---------------+------------------+
Quindi nella nostra soluzione alternativa, DATEDIFF()
ha utilizzato la “Data risultante” nei suoi calcoli.
Se hai riscontrato problemi con DATEDIFF()
ignorando SET DATEFIRST
, si spera che questo articolo sia stato di aiuto.