Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Eine Problemumgehung für DATEDIFF(), die SET DATEFIRST in SQL Server ignoriert (T-SQL-Beispiel)

Eine interessante Sache über DATEDIFF() Funktion in SQL Server besteht darin, dass Ihr SET DATEFIRST ignoriert wird Wert.

Dies ist jedoch kein Fehler. Dokumentation von Microsoft für DATEDIFF() heißt es eindeutig:

Angabe von SET DATEFIRST hat keine Auswirkung auf DATEDIFF . DATEDIFF verwendet immer den Sonntag als ersten Tag der Woche, um sicherzustellen, dass die Funktion deterministisch arbeitet.

Falls Sie es nicht wissen, SET DATEFIRST legt den ersten Tag der Woche für Ihre Sitzung fest. Es ist eine Zahl von 1 bis 7 (was Montag bis Sonntag entspricht).

Der Anfangswert für SET DATEFIRST wird implizit durch die Spracheinstellung gesetzt (die Sie mit SET LANGUAGE einstellen können Erklärung). Der tatsächliche Wert hängt von der eingestellten Sprache ab. Zum Beispiel der Standardwert für us_english Sprache ist 7 (Sonntag), während die Standardeinstellung für British Sprache ist 1 (Montag).

Sie können jedoch ein SET DATEFIRST verwenden -Anweisung, um dies zu überschreiben, sodass Sie weiterhin dieselbe Sprache verwenden können, während Sie für den ersten Tag der Woche einen anderen Tag verwenden.

Aber wie gesagt, das SET DATEFIRST Wert hat keine Auswirkung auf DATEDIFF() Funktion. Das DATEDIFF() Die Funktion geht immer davon aus, dass Sonntag der erste Tag der Woche ist, unabhängig von Ihrem SET DATEFIRST Wert.

Dies kann einige interessante Probleme bei der Verwendung von DATEDIFF() verursachen wenn Sie nicht wissen, wie es funktioniert.

Wenn Sie sich in dieser Situation befinden, können die Beispiele auf dieser Seite hoffentlich helfen.

Beispiel 1 – Das Problem

Hier ist zunächst ein Beispiel für das eigentliche Problem. Beachten Sie, dass wir SET DATEFIRST abrufen können Wert, indem Sie @@DATEFIRST auswählen .

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

Ergebnis:

+-----------------------+--------------------- ----------+| SET DATEFIRST Wert | us_english DATEDIFF() Ergebnis ||-----------------------+------------------- -------------|| 7 | 0 |+----------------------+------------------------------- --------++-----------------------+--------------- --------------+| SET DATEFIRST Wert | Britisch DATEDIFF() Ergebnis ||---------------------+------------------- ----------|| 1 | 0 |+----------------------+------------------------------- ------+

In diesem Fall fällt der erste Termin auf einen Sonntag und der zweite Termin auf einen Montag. Daher würden Sie normalerweise das britische DATEDIFF() erwarten Ergebnis, um 1 zurückzugeben . Sie würden dies erwarten, weil die Wochenteilgrenze überschritten wird, wenn sie von Sonntag auf Montag geht (weil die SET DATEFIRST Wert ist 1 was „Montag“ bedeutet, und Montag markiert den Beginn einer neuen Woche).

Aber weil DATEDIFF() ignoriert Ihr SET DATEFIRST -Wert und davon ausgeht, dass Sonntag der Wochenbeginn ist, erhalten wir das gleiche Ergebnis für beide Sprachen.

Nur um sicherzugehen, führe ich die Abfrage noch einmal aus, aber dieses Mal setze ich den SET DATEFIRST Wert explizit . Mit anderen Worten, anstatt die Sprache festzulegen, verwende ich den SET DATEFIRST Aussage:

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

Ergebnis:

+-----------------------+--------------------- ----------+| SET DATEFIRST Wert | us_english DATEDIFF() Ergebnis ||-----------------------+------------------- -------------|| 7 | 0 |+----------------------+------------------------------- --------++-----------------------+--------------- --------------+| SET DATEFIRST Wert | Britisch DATEDIFF() Ergebnis ||---------------------+------------------- ----------|| 1 | 0 |+----------------------+------------------------------- ------+

Dasselbe Ergebnis, auch wenn Sie explizit SET DATEFIRST setzen Wert. Das ist jedoch keine Überraschung – ich wäre überrascht, wenn es nicht wäre das gleiche Ergebnis zurückgeben.

Außerdem bestätigt dies einfach, dass DATEDIFF() funktioniert genau wie beabsichtigt.

Wie ändern wir es also, damit unser DATEDIFF() Ergebnisse ehren unser SET DATEFIRST Wert?

Die Lösung

Hier ist eine Lösung / Problemumgehung, mit der Sie die beabsichtigten Ergebnisse erzielen können. Dadurch wird sichergestellt, dass Ihr SET DATEFIRST Einstellungen werden in Ihr DATEDIFF() eingerechnet Ergebnisse.

Alles, was Sie tun müssen, ist @@DATEFIRST zu subtrahieren aus den Eingabedaten.

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

Ergebnis:

+-----------------------+--------------------- ----------+| SET DATEFIRST Wert | us_english DATEDIFF() Ergebnis ||-----------------------+------------------- -------------|| 7 | 0 |+----------------------+------------------------------- --------++-----------------------+--------------- --------------+| SET DATEFIRST Wert | Britisch DATEDIFF() Ergebnis ||---------------------+------------------- ----------|| 1 | 1 |+-----------------------+------------------------------- ------+

Dies verwendet das DATEADD() Funktion, um die Eingabedaten um den Betrag von @@DATEFIRST zu reduzieren (das ist Ihr SET DATEFIRST Wert).

In diesem Fall das DATEDIFF() Die Funktion verwendet immer noch den Sonntag als ersten Tag der Woche, die tatsächlichen Daten, die in der Berechnung verwendet werden, sind jedoch unterschiedlich. Sie wurden um den Betrag von @@DATEFIRST in der Zeit zurückversetzt .

Das folgende Beispiel zeigt die Datumsangaben, die in der Berechnung verwendet wurden:

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 ALLSELECT @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 'Ergebnisdatum'UNION ALLSELECT @enddate, @@DATEFIRST , DATEADD(day, [email protected]@DATEFIRST, @enddate); 

Ergebnis:

+------------+---------------+------------ ------+| Ursprüngliches Datum | Subtrahieren nach | Ergebnisdatum ||-----------------+---------------+------------ ------|| 05.01.2025 | 7 | 2024-12-29 || 06.01.2025 | 7 | 2024-12-30 |+----------------+---------------+--------- ---------++----------------+---------------+----- -------------+| Ursprüngliches Datum | Subtrahieren nach | Ergebnisdatum ||-----------------+---------------+------------ ------|| 05.01.2025 | 1 | 04.01.2025 || 06.01.2025 | 1 | 2025-01-05 |+----------------+---------------+--------- ---------+

In unserer Problemumgehung also DATEDIFF() verwendet das „Ergebnisdatum“ in seinen Berechnungen.

Wenn Sie auf Probleme mit DATEDIFF() gestoßen sind Ignorieren von SET DATEFIRST , hoffentlich hat dieser Artikel geholfen.