Zajímavá věc o DATEDIFF() funkce v SQL Server je, že ignoruje váš SET DATEFIRST hodnota.
To však není chyba. Dokumentace společnosti Microsoft pro DATEDIFF() jasně uvádí následující:
Zadání
SET DATEFIRSTnemá žádný vliv naDATEDIFF.DATEDIFFvždy používá neděli jako první den v týdnu, aby bylo zajištěno, že funkce funguje deterministickým způsobem.
V případě, že nevíte, SET DATEFIRST nastaví první den v týdnu pro vaši relaci. Je to číslo od 1 do 7 (což odpovídá pondělí až neděli).
Počáteční hodnota pro SET DATEFIRST je implicitně nastaveno nastavením jazyka (které můžete nastavit pomocí SET LANGUAGE prohlášení). Skutečná hodnota bude záviset na nastaveném jazyce. Například výchozí hodnota pro us_english jazyk je 7 (neděle), zatímco výchozí pro British jazyk je 1 (Pondělí).
Můžete však použít SET DATEFIRST toto přepíšete, abyste mohli nadále používat stejný jazyk a zároveň používat jiný den pro první den v týdnu.
Ale jak již bylo zmíněno, SET DATEFIRST hodnota nemá žádný vliv na DATEDIFF() funkce. DATEDIFF() funkce vždy předpokládá, že neděle je prvním dnem v týdnu bez ohledu na SET DATEFIRST hodnotu.
To může způsobit zajímavé problémy při použití DATEDIFF() pokud nevíte, jak to funguje.
Pokud se ocitnete v této situaci, doufejme, že příklady na této stránce vám pomohou.
Příklad 1 – Problém
Nejprve je zde příklad skutečného problému. Všimněte si, že můžeme načíst SET DATEFIRST hodnotu výběrem @@DATEFIRST .
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET LANGUAGE us_english;SELECT @@DATEFIRST JAKO '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';
Výsledek:
+-----------------------+---------------------- ----------+| SET DATEFIRST Hodnota | us_english DATEDIFF() Výsledek ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+------------------------ ---------++-----------------------+--------------- ---------------+| SET DATEFIRST Hodnota | Britský výsledek DATEDIFF() ||-----------------------+------------------- ----------|| 1 | 0 |+-----------------------+------------------------ ------+
V tomto případě první datum připadá na neděli a druhé datum na pondělí. Proto byste normálně očekávali britské DATEDIFF() výsledek vrátí 1 . Očekávali byste to, protože hranice týdenní části je překročena, když jde od neděle do pondělí (protože SET DATEFIRST hodnota je 1 což znamená „pondělí“ a pondělí znamená začátek nového týdne).
Ale protože DATEDIFF() ignoruje váš SET DATEFIRST a předpokládá, že neděle je začátkem týdne, dostaneme stejný výsledek pro oba jazyky.
Pro jistotu spustím dotaz znovu, ale tentokrát nastavím SET DATEFIRST hodnotu explicitně . Jinými slovy, místo nastavení jazyka použiji SET DATEFIRST prohlášení:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST JAKO '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';
Výsledek:
+-----------------------+---------------------- ----------+| SET DATEFIRST Hodnota | us_english DATEDIFF() Výsledek ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+------------------------ ---------++-----------------------+--------------- ---------------+| SET DATEFIRST Hodnota | Britský výsledek DATEDIFF() ||-----------------------+------------------- ----------|| 1 | 0 |+-----------------------+------------------------ ------+
Stejný výsledek, i když explicitně nastavíte SET DATEFIRST hodnota. To však není žádné překvapení – byl bych překvapen, kdyby nebylo vrátit stejný výsledek.
Také to jednoduše potvrzuje, že DATEDIFF() funguje přesně tak, jak bylo zamýšleno.
Jak to tedy změníme, aby naše DATEDIFF() výsledky respektují naše SET DATEFIRST hodnotu?
Řešení
Zde je řešení/obcházení, které vám umožní dosáhnout zamýšlených výsledků. Tím zajistíte, že SET DATEFIRST nastavení jsou zohledněna ve vašem DATEDIFF() Výsledek.
Vše, co musíte udělat, je odečíst @@DATEFIRST ze vstupních dat.
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, DATEADD(den) , example@sqldat.com@DATEFIRST, @startdate), DATEADD(den, example@sqldat.com@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Hodnota', DATEDIFF(týden, DATEADD(den, example@sqldat.com@DATEFIRST, @startdate), DATEADD(den, example@sqldat.com@DATEFIRST, @enddate)) AS 'British DATEDIFF() Result';Výsledek:
+-----------------------+---------------------- ----------+| SET DATEFIRST Hodnota | us_english DATEDIFF() Výsledek ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+------------------------ ---------++-----------------------+--------------- ---------------+| SET DATEFIRST Hodnota | Britský výsledek DATEDIFF() ||-----------------------+------------------- ----------|| 1 | 1 |+-----------------------+------------------------ ------+Toto používá
DATEADD()funkce ke snížení vstupních dat o hodnotu@@DATEFIRST(což je vašeSET DATEFIRSThodnota).V tomto případě
DATEDIFF()funkce stále používá neděli jako první den v týdnu, avšak skutečná data použitá ve výpočtu se liší. Byly posunuty zpět v čase o hodnotu@@DATEFIRST.Následující příklad ukazuje data, která byla použita při výpočtu:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @startdate AS 'Původní datum', @@DATEFIRST AS 'Odečíst do', DATEADD(den, example@sqldat.com@DATEFIRST, @startdate) AS 'Výsledné datum'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(den, example@sqldat.com@DATEFIRST, @enddate); SET DATEFIRST 1;SELECT @startdate AS 'Původní datum', @@DATEFIRST AS 'Odečíst do', DATEADD(den, příklad@sqldat.com@DATEFIRST, @startdate) JAKO 'Výsledné datum'UNION ALLSELECT @enddate, DATEFIRST , DATEADD(den, example@sqldat.com@DATEFIRST, @enddate);Výsledek:
+-----------------+---------------+------------- ------+| Původní datum | Odečíst od | Výsledné datum ||-----------------+---------------+------------ ------|| 2025-01-05 | 7 | 2024-12-29 || 2025-01-06 | 7 | 2024-12-30 |+-----------------+---------------+---------- ---------++-----------------+----------------+----- -------------+| Původní datum | Odečíst od | Výsledné datum ||-----------------+---------------+------------ ------|| 2025-01-05 | 1 | 2025-01-04 || 2025-01-06 | 1 | 2025-01-05 |+-----------------+---------------+---------- ---------+Takže v našem řešení
DATEDIFF()ve svých výpočtech použila „Výsledné datum“.Pokud jste narazili na problémy s
DATEDIFF()ignorováníSET DATEFIRST, doufám, že vám tento článek pomohl.