sql >> Database >  >> RDS >> Sqlserver

Een tijdelijke oplossing voor DATEDIFF() SET DATEFIRST negeren in SQL Server (T-SQL-voorbeeld)

Een interessant ding over de DATEDIFF() functie in SQL Server is dat het uw SET DATEFIRST . negeert waarde.

Dit is echter geen bug. Microsoft-documentatie voor DATEDIFF() staat duidelijk het volgende:

Specificeren SET DATEFIRST heeft geen effect op DATEDIFF . DATEDIFF gebruikt altijd zondag als de eerste dag van de week om ervoor te zorgen dat de functie op een deterministische manier werkt.

Voor het geval je het niet weet, SET DATEFIRST stelt de eerste dag van de week in voor uw sessie. Het is een getal van 1 tot en met 7 (wat overeenkomt met maandag tot en met zondag).

De beginwaarde voor SET DATEFIRST wordt impliciet ingesteld door de taalinstelling (die u kunt instellen met de SET LANGUAGE uitspraak). De werkelijke waarde is afhankelijk van de taal die is ingesteld. Bijvoorbeeld de standaardwaarde voor de us_english taal is 7 (zondag), terwijl de standaard voor de British taal is 1 (Maandag).

U kunt echter een SET DATEFIRST . gebruiken verklaring om dit te negeren, zodat u dezelfde taal kunt blijven gebruiken terwijl u de eerste dag van de week een andere dag gebruikt.

Maar zoals gezegd, de SET DATEFIRST waarde heeft geen effect op de DATEDIFF() functie. De DATEDIFF() functie gaat er altijd van uit dat zondag de eerste dag van de week is, ongeacht uw SET DATEFIRST waarde.

Dit kan interessante problemen veroorzaken bij het gebruik van DATEDIFF() als je niet weet hoe het werkt.

Als u zich in deze situatie bevindt, kunnen de voorbeelden op deze pagina hopelijk helpen.

Voorbeeld 1 – Het probleem

Ten eerste is hier een voorbeeld van het werkelijke probleem. Merk op dat we de SET DATEFIRST . kunnen ophalen waarde door @@DATEFIRST te selecteren .

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

Resultaat:

+-----------------------+--------------------------------+
| SET DATEFIRST Value   | us_english DATEDIFF() Result   |
|-----------------------+--------------------------------|
| 7                     | 0                              |
+-----------------------+--------------------------------+

+-----------------------+-----------------------------+
| SET DATEFIRST Value   | British DATEDIFF() Result   |
|-----------------------+-----------------------------|
| 1                     | 0                           |
+-----------------------+-----------------------------+

In dit geval valt de eerste datum op een zondag en de tweede datum op een maandag. Daarom zou je normaal gesproken de Britse DATEDIFF() . verwachten resultaat om 1 te retourneren . Je zou dit verwachten omdat de grens van het weekgedeelte wordt overschreden wanneer het van zondag naar maandag gaat (omdat de SET DATEFIRST waarde is 1 wat "maandag" betekent, en maandag markeert het begin van een nieuwe week).

Maar omdat DATEDIFF() negeert je SET DATEFIRST waarde en veronderstelt dat zondag het begin van de week is, krijgen we hetzelfde resultaat voor beide talen.

Voor de zekerheid zal ik de query opnieuw uitvoeren, maar deze keer stel ik de SET DATEFIRST in waarde expliciet . Met andere woorden, in plaats van de taal in te stellen, gebruik ik de SET DATEFIRST verklaring:

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

Resultaat:

+-----------------------+--------------------------------+
| SET DATEFIRST Value   | us_english DATEDIFF() Result   |
|-----------------------+--------------------------------|
| 7                     | 0                              |
+-----------------------+--------------------------------+

+-----------------------+-----------------------------+
| SET DATEFIRST Value   | British DATEDIFF() Result   |
|-----------------------+-----------------------------|
| 1                     | 0                           |
+-----------------------+-----------------------------+

Hetzelfde resultaat, zelfs als je expliciet de SET DATEFIRST . instelt waarde. Dit is echter geen verrassing - het zou me verbazen als het niet hetzelfde resultaat teruggeven.

Dit bevestigt ook eenvoudig dat DATEDIFF() werkt precies zoals bedoeld.

Dus, hoe veranderen we het zodat onze DATEDIFF() resultaten eren onze SET DATEFIRST waarde?

De oplossing

Hier is een oplossing / tijdelijke oplossing waarmee u de beoogde resultaten kunt krijgen. Dit zorgt ervoor dat uw SET DATEFIRST instellingen worden verwerkt in uw DATEDIFF() resultaten.

Het enige wat je hoeft te doen is @@DATEFIRST . af te trekken vanaf de invoerdata.

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

Resultaat:

+-----------------------+--------------------------------+
| SET DATEFIRST Value   | us_english DATEDIFF() Result   |
|-----------------------+--------------------------------|
| 7                     | 0                              |
+-----------------------+--------------------------------+

+-----------------------+-----------------------------+
| SET DATEFIRST Value   | British DATEDIFF() Result   |
|-----------------------+-----------------------------|
| 1                     | 1                           |
+-----------------------+-----------------------------+

Dit gebruikt de DATEADD() functie om de invoerdatums te verminderen met het aantal @@DATEFIRST (dat is je SET DATEFIRST waarde).

In dit geval de DATEDIFF() functie gebruikt nog steeds de zondag als de eerste dag van de week, maar de werkelijke datums die in de berekening worden gebruikt, zijn anders. Ze zijn terug in de tijd verplaatst met een bedrag van @@DATEFIRST .

Het volgende voorbeeld toont de datums die in de berekening zijn gebruikt:

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

Resultaat:

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

Dus in onze tijdelijke oplossing, DATEDIFF() gebruikte de "Resulterende datum" in zijn berekeningen.

Als u problemen ondervindt met DATEDIFF() negeren SET DATEFIRST , hopelijk heeft dit artikel geholpen.


  1. Virtuele index gebruiken in Oracle Database

  2. Mysql-toestemmingsfouten met 'gegevens laden'

  3. Methoden voor exporteren en importeren van SQL Server-databasetabellen

  4. Verschil tussen Oracle's plus (+) notatie en ansi JOIN notatie?