DATEDIFF()
の興味深い点 SQL Serverの機能は、SET DATEFIRST
を無視することです。 価値。
ただし、これはバグではありません。 DATEDIFF()
に関するMicrosoftのドキュメント 次のことを明確に述べています:
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'; 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';
結果:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
この場合、最初の日付は日曜日になり、2番目の日付は月曜日になります。したがって、通常は英国のDATEDIFF()
を期待します。 1
を返す結果 。これは、日曜日から月曜日に行くときに週と部分の境界を越えるためです(SET DATEFIRST
のため) 値は1
です これは「月曜日」を意味し、月曜日は新しい週の始まりを示します)。
ただし、DATEDIFF()
SET DATEFIRST
を無視します 値であり、日曜日が週の始まりであると想定すると、両方の言語で同じ結果が得られます。
念のため、もう一度クエリを実行しますが、今回はSET DATEFIRST
を設定します。 値明示的に 。つまり、言語を設定する代わりに、SET DATEFIRST
を使用します ステートメント:
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';
結果:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
SET DATEFIRST
を明示的に設定した場合でも、同じ結果になります 価値。ただし、これは驚くべきことではありません。そうでなかった場合は驚きます。 同じ結果を返します。
また、これは単にDATEDIFF()
であることを確認します 意図したとおりに機能しています。
では、DATEDIFF()
になるように変更するにはどうすればよいですか。 結果はSET DATEFIRST
を尊重します 値?
ソリューション
意図した結果を得ることができる解決策/回避策は次のとおりです。これにより、SET DATEFIRST
が確実になります 設定はDATEDIFF()
に組み込まれます 結果。
あなたがする必要があるのは@@DATEFIRST
を引くことだけです 入力日から。
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';
結果:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 1 | +-----------------------+-----------------------------+
これはDATEADD()
を使用します @@DATEFIRST
の量だけ入力日付を減らす関数 (これはSET DATEFIRST
値)。
この場合、DATEDIFF()
関数は引き続き日曜日を週の最初の日として使用しますが、計算に使用される実際の日付は異なります。 @@DATEFIRST
の量だけ過去に戻されました 。
次の例は、計算に使用された日付を示しています。
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);
結果:
+-----------------+---------------+------------------+ | 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 | +-----------------+---------------+------------------+
したがって、回避策では、DATEDIFF()
計算には「結果の日付」を使用しました。
DATEDIFF()
で問題が発生した場合 SET DATEFIRST
を無視します 、この記事がお役に立てば幸いです。