En interessant ting ved DATEDIFF()
funktion i SQL Server er, at den ignorerer din SET DATEFIRST
værdi.
Dette er dog ikke en fejl. Microsofts dokumentation for DATEDIFF()
står klart følgende:
Angivelse af SET DATEFIRST
har ingen effekt på DATEDIFF
. DATEDIFF
bruger altid søndag som den første dag i ugen for at sikre, at funktionen fungerer på en deterministisk måde.
I tilfælde af at du ikke ved det, SET DATEFIRST
indstiller den første dag i ugen for din session. Det er et tal fra 1 til 7 (hvilket svarer til mandag til søndag).
Startværdien for SET DATEFIRST
er implicit indstillet af sprogindstillingen (som du kan indstille med SET LANGUAGE
udmelding). Den faktiske værdi afhænger af det indstillede sprog. For eksempel standardværdien for us_english
sproget er 7
(søndag), mens standarden for British
sproget er 1
(Mandag).
Du kan dog bruge en SET DATEFIRST
erklæring for at tilsidesætte dette, så du kan fortsætte med at bruge det samme sprog, mens du bruger en anden dag på den første dag i ugen.
Men som nævnt er SET DATEFIRST
værdi har ingen effekt på DATEDIFF()
fungere. DATEDIFF()
funktionen antager altid, at søndag er den første dag i ugen uanset din SET DATEFIRST
værdi.
Dette kan forårsage nogle interessante problemer, når du bruger DATEDIFF()
hvis du ikke ved, hvordan det virker.
Hvis du befinder dig i denne situation, kan eksemplerne på denne side forhåbentlig hjælpe.
Eksempel 1 – Problemet
For det første er her et eksempel på det faktiske problem. Bemærk, at vi kan hente SET DATEFIRST
værdi ved at vælge @@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';
Resultat:
+------------------------+---------- ----------+| SET DATEFIRST Værdi | us_english DATEDIFF() Resultat ||----------------------------+------------------------ --------------|| 7 | 0 |+------------------------+---------- -----------++-------------------------+--------- --------------+| SET DATEFIRST Værdi | Britisk DATEDIFF() Resultat ||-----------------------------+------------------------ ----------|| 1 | 0 |+------------------------+---------- ------+
I dette tilfælde falder den første dato på en søndag og den anden dato på en mandag. Derfor ville du normalt forvente den britiske DATEDIFF()
resultat for at returnere 1
. Du ville forvente dette, fordi uge-del-grænsen krydses, når den går fra søndag til mandag (fordi SET DATEFIRST
værdien er 1
hvilket betyder "mandag", og mandag markerer starten på en ny uge).
Men fordi DATEDIFF()
ignorerer din SET DATEFIRST
værdi og antager, at søndag er starten på ugen, får vi det samme resultat for begge sprog.
For at være sikker kører jeg forespørgslen igen, men denne gang indstiller jeg SET DATEFIRST
værdi eksplicit . Med andre ord, i stedet for at indstille sproget, bruger jeg SET DATEFIRST
erklæring:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(uge, @startdate, @enddate) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
Resultat:
+------------------------+---------- ----------+| SET DATEFIRST Værdi | us_english DATEDIFF() Resultat ||----------------------------+------------------------ --------------|| 7 | 0 |+------------------------+---------- -----------++-------------------------+--------- --------------+| SET DATEFIRST Værdi | Britisk DATEDIFF() Resultat ||-----------------------------+------------------------ ----------|| 1 | 0 |+------------------------+---------- ------+
Samme resultat, selv når du udtrykkeligt indstiller SET DATEFIRST
værdi. Dette er dog ingen overraskelse – jeg ville blive overrasket, hvis det ikke gjorde returnere det samme resultat.
Dette bekræfter også blot, at DATEDIFF()
fungerer nøjagtigt efter hensigten.
Så hvordan ændrer vi det, så vores DATEDIFF()
resultater ære vores SET DATEFIRST
værdi?
Løsningen
Her er en løsning/løsning, der giver dig mulighed for at få de tilsigtede resultater. Dette vil sikre, at din SET DATEFIRST
indstillinger er indregnet i din DATEDIFF()
resultater.
Alt du skal gøre er at trække @@DATEFIRST
fra fra inputdatoerne.
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(uge, DATEADD(dag) , [email protected]@DATEFIRST, @startdato), DATEADD(dag, [email protected]@DATEFIRST, @slutdato)) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(uge, DATEADD(dag, [email protected]@DATEFIRST, @startdato), DATEADD(dag, [email protected]@DATEFIRST, @slutdato)) SOM 'British DATEDIFF() Result';Resultat:
+------------------------+---------- ----------+| SET DATEFIRST Værdi | us_english DATEDIFF() Resultat ||----------------------------+------------------------ --------------|| 7 | 0 |+------------------------+---------- -----------++-------------------------+--------- --------------+| SET DATEFIRST Værdi | Britisk DATEDIFF() Resultat ||-----------------------------+------------------------ ----------|| 1 | 1 |+------------------------+---------- ------+Dette bruger
DATEADD()
funktion til at reducere inputdatoer med mængden@@DATEFIRST
(som er dinSET DATEFIRST
værdi).I dette tilfælde
DATEDIFF()
funktion bruger stadig søndag som den første dag i ugen, dog er de faktiske datoer, der bruges i beregningen, forskellige. De er blevet flyttet tilbage i tiden med mængden@@DATEFIRST
.Følgende eksempel viser de datoer, der blev brugt i beregningen:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(dag, [email protected]@DATEFIRST, @startdato) AS 'Resultatdato'UNION ALLSELECT @slutdato, @@DATOFIRST, DATEADD(dag, [email protected]@DATEFIRST, @slutdato); INDSTIL DATEFIRST 1;VÆLG @startdato SOM 'Original Dato', @@DATEFIRST SOM 'Subtract By', DATEADD(dag, [email protected]@DATEFIRST, @startdato) SOM 'Resultatdato'UNION ALLSELECT @slutdato, @@DATEFIRST , DATEADD(dag, [email protected]@DATEFIRST, @slutdato);Resultat:
+----------------+----------------- ------+| Original dato | Træk fra ved | Resultatdato ||----------------+--------------+------------ ------|| 05-01-2025 | 7 | 29-12-2024 || 06-01-2025 | 7 | 30-12-2024 |+----------------+----------------- ----------++----------------+--------------+----- --------------+| Original dato | Træk fra ved | Resultatdato ||----------------+--------------+------------ ------|| 2025-01-05 | 1 | 04-01-2025 || 06-01-2025 | 1 | 2025-01-05 |+----------------+------------------+-------- ----------+Så i vores løsning,
DATEDIFF()
brugte "Resultatdatoen" i sine beregninger.Hvis du er løbet ind i problemer med
DATEDIFF()
ignorererSET DATEFIRST
, forhåbentlig hjalp denne artikel.