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 DATEFIRST
nemá žádný vliv naDATEDIFF
.DATEDIFF
vž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) , [email protected]@DATEFIRST, @startdate), DATEADD(den, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Hodnota', DATEDIFF(týden, DATEADD(den, [email protected]@DATEFIRST, @startdate), DATEADD(den, [email protected]@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 DATEFIRST
hodnota).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, [email protected]@DATEFIRST, @startdate) AS 'Výsledné datum'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(den, [email protected]@DATEFIRST, @enddate); SET DATEFIRST 1;SELECT @startdate AS 'Původní datum', @@DATEFIRST AS 'Odečíst do', DATEADD(den, pří[email protected]@DATEFIRST, @startdate) JAKO 'Výsledné datum'UNION ALLSELECT @enddate, DATEFIRST , DATEADD(den, [email protected]@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.