Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Заобиколно решение за DATEDIFF() игнориране на SET DATEFIRST в SQL Server (пример за T-SQL)

Интересно нещо за DATEDIFF() функция в SQL Server е, че той игнорира вашия SET DATEFIRST стойност.

Това обаче не е грешка. Документацията на Microsoft за DATEDIFF() ясно посочва следното:

Посочване на SET DATEFIRST няма ефект върху DATEDIFF . DATEDIFF винаги използва неделя като първи ден от седмицата, за да гарантира, че функцията работи по детерминиран начин.

В случай, че не знаете, SET DATEFIRST задава първия ден от седмицата за вашата сесия. Това е число от 1 до 7 (което съответства на понеделник до неделя).

Първоначалната стойност за SET DATEFIRST се задава имплицитно от настройката за език (която можете да зададете с SET LANGUAGE изявление). Действителната стойност ще зависи от езика, който е зададен. Например стойността по подразбиране за us_english езикът е 7 (неделя), докато по подразбиране за British езикът е 1 (понеделник).

Можете обаче да използвате SET DATEFIRST изявление, за да замените това, за да можете да продължите да използвате същия език, докато използвате различен ден за първия ден от седмицата.

Но както споменахме, SET DATEFIRST стойността няма ефект върху DATEDIFF() функция. DATEDIFF() функцията винаги приема, че неделя е първият ден от седмицата, независимо от SET DATEFIRST стойност.

Това може да причини някои интересни проблеми при използване на DATEDIFF() ако не знаете как работи.

Ако се окажете в тази ситуация, надявам се примерите на тази страница да ви помогнат.

Пример 1 – Проблемът

Първо, ето пример за действителния проблем. Имайте предвид, че можем да извлечем SET DATEFIRST стойност, като изберете @@DATEFIRST .

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';ЗАДАДЕТЕ ЕЗИК us_english;ИЗБЕРЕТЕ @@DATEFIRST КАТО 'ЗАДАВАНЕ НА DATEFIRST стойност', DATEDIFF(седмица, @startdate, @enddate) КАТО 'us_english DATEDIFF() Резултат';ЗАДАДЕТЕ ЕЗИК британски;ИЗБЕРЕТЕ @@DATEFIRST КАТО 'ЗАДАВАНЕ НА DATEFIRST стойност', DATEDIFF(седмица, @startdate, @enddate) КАТО 'британски DATEDIFF() резултат';

Резултат:

+-----------------------+--------------------- ----------+| SET DATEFIRST Стойност | us_english DATEDIFF() Резултат ||-----------------------+------------------- ------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+-------------- --------------+| SET DATEFIRST Стойност | Британски DATEDIFF() Резултат ||-----------------------+------------------ ----------|| 1 | 0 |+-----------------------+----------------------- ------+

В този случай първата дата е в неделя, а втората в понеделник. Следователно обикновено очаквате британския DATEDIFF() резултат за връщане на 1 . Бихте очаквали това, защото границата на седмичната част се пресича, когато преминава от неделя до понеделник (защото SET DATEFIRST стойността е 1 което означава „понеделник“, а понеделник бележи началото на нова седмица).

Но тъй като DATEDIFF() игнорира вашия SET DATEFIRST стойност и приема, че неделя е началото на седмицата, получаваме същия резултат и за двата езика.

Само за да съм сигурен, ще изпълня заявката отново, но този път ще задам SET DATEFIRST стойност изрично . С други думи, вместо да задавам езика, ще използвам SET DATEFIRST изявление:

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';ЗАДАДЕТЕ DATEFIRST 7;ИЗБЕРЕТЕ @@DATEFIRST КАТО 'ЗАДАВАНЕ НА DATEFIRST стойност', DATEDIFF(седмица, @startdate, @enddate) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';

Резултат:

+-----------------------+--------------------- ----------+| SET DATEFIRST Стойност | us_english DATEDIFF() Резултат ||-----------------------+------------------- ------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+-------------- --------------+| SET DATEFIRST Стойност | Британски DATEDIFF() Резултат ||-----------------------+------------------ ----------|| 1 | 0 |+-----------------------+----------------------- ------+

Същият резултат, дори когато изрично зададете SET DATEFIRST стойност. Това обаче не е изненада – бих се изненадал, ако не беше върнете същия резултат.

Също така, това просто потвърждава, че DATEDIFF() работи точно както е предвидено.

И така, как да го променим така, че нашият DATEDIFF() резултатите отговарят на нашия SET DATEFIRST стойност?

Решението

Ето решение/заобиколно решение, което ще ви позволи да получите очакваните резултати. Това ще гарантира, че вашият SET DATEFIRST настройките са включени във вашия DATEDIFF() резултати.

Всичко, което трябва да направите, е да извадите @@DATEFIRST от въведените дати.

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';ЗАДАДЕТЕ DATEFIRST 7;ИЗБЕРЕТЕ @@DATEFIRST КАТО 'ЗАДАВАНЕ НА DATEFIRST стойност', DATEDIFF(седмица, DATEADD(ден , [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Стойност“, DATEDIFF(седмица, DATEADD(ден, [email protected]@DATEFIRST, @startdate), DATEADD(ден, [email protected]@DATEFIRST, @enddate)) КАТО „британски резултат DATEDIFF()“; 

Резултат:

+-----------------------+--------------------- ----------+| SET DATEFIRST Стойност | us_english DATEDIFF() Резултат ||-----------------------+------------------- ------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+-------------- --------------+| SET DATEFIRST Стойност | Британски DATEDIFF() Резултат ||-----------------------+------------------ ----------|| 1 | 1 |+-----------------------+----------------------- ------+

Това използва DATEADD() функция за намаляване на въведените дати с количеството @@DATEFIRST (което е вашият SET DATEFIRST стойност).

В този случай DATEDIFF() функцията все още използва неделя като първи ден от седмицата, но действителните дати, използвани в изчислението, са различни. Те са преместени назад във времето с количеството @@DATEFIRST .

Следният пример показва датите, използвани при изчислението:

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';ЗАДАДЕТЕ DATEFIRST 7;ИЗБЕРЕТЕ @startdate КАТО 'Оригинална дата', @@DATEFIRST КАТО 'Извадете по', DATEADD(ден, пример@sqldat.com@DATEFIRST, @startdate) КАТО 'Резултна дата'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(ден, [email protected]@DATEFIRST, @enddate); ЗАДАЙТЕ DATEFIRST 1;ИЗБЕРЕТЕ @startdate КАТО 'Оригинална дата', @@DATEFIRST КАТО 'Извадете по', DATEADD(ден, [email protected]@DATEFIRST, @startdate) КАТО 'Резултна дата'UNION ALLSELECT @enddate, @@DATEFIRST , DATEADD(ден, пример@sqldat.com@DATEFIRST, @крайна дата); 

Резултат:

+-----------------+--------------+----------- ------+| Оригинална дата | Изваждане по | Резултатна дата ||-----------------+--------------+------------ ------|| 2025-01-05 | 7 | 29.12.2024 || 2025-01-06 | 7 | 2024-12-30 |+----------------+--------------+-------- ---------++----------------+--------------+----- ------------+| Оригинална дата | Изваждане по | Резултатна дата ||-----------------+--------------+------------ ------|| 2025-01-05 | 1 | 2025-01-04 || 2025-01-06 | 1 | 2025-01-05 |+----------------+--------------+-------- ---------+

Така че в нашето заобиколно решение, DATEDIFF() използва „Резултатна дата“ в своите изчисления.

Ако сте срещали проблеми с DATEDIFF() игнорирайки SET DATEFIRST , надявам се тази статия да е помогнала.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да нулирате стойността на колоната за идентичност в таблицата на SQL Server - SQL Server / T-SQL урок, част 43

  2. Именуван екземпляр на SQL Server с проект на Visual Studio 2017 Installer

  3. Как да изпълним една и съща заявка във всички бази данни на даден екземпляр?

  4. Получаване на върната стойност от съхранената процедура в C#

  5. Типове курсори на SQL Server - KEYSET Курсор | Урок за SQL Server / Урок за TSQL