したがって、私たちのデータチームは、彼らが抱えている問題を解決するための支援を求めました。最終的には、実際に範囲外のデータ(1/1/0001)と、それらが使用していたDATEDIFF関数まで追跡しました。私は彼らの問題を解決しましたが、彼らがそれを使用していたときに使用されたときに実際に0が何に変わるかわからないということが起こりました。
もともとは真の変換エラーというよりは整数オーバーフローに近いと思っていましたが、それだけではありません。 SQL 2016ボックスでDATEDIFF_BIGと同じエラーを試してみました。以下のサンプルで、機能するものと機能しないものを一緒に試してみましょう。
/** Setup The Sample */
DECLARE @TestValue DATETIME2(7)
SET @TestValue = '0001-01-01 10:30:00.0000000'
/** Conversion Error
Msg 242, Level 16, State 3, Line 10
The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
*/
SELECT DATEDIFF(MINUTE, 0, @TestValue)
--Also does not work, same error.
SELECT DATEDIFF_BIG(MINUTE, 0, @TestValue)
/** Works */
SELECT DATEDIFF(MINUTE, '1/1/1900', @TestValue)
/** Works */
SELECT DATEDIFF(MINUTE, CAST(0 AS DATETIME), @TestValue)
/** Doesn't Work, you can't cast 0 to a DATETIME2 */
--SELECT DATEDIFF(MINUTE, CAST(0 AS DATETIME2), @TestValue)
/** Works (or no error, which is fine)*/
SELECT DATEDIFF(MINUTE, 0, TRY_CAST(@TestValue AS DATETIME))
ボーナス質問、0はDATETIME2のすべてのケースで機能するわけではないので、代替手段は何ですか?
WHAT WE実行することを決定
したがって、datemathの多くの例(月の最初の日など)に0が表示されるため、次のことをチームに勧めることを始めました。したがって、0からdatetimeへの明示的なキャストを行ってから、続行することをお勧めします。これにより、作業中のエラーを回避できます。そう:
DATEDIFF(MINUTE, CAST(DATETIME, 0), <Date>)
FROM
句を使用してクエリに式を追加し、計算スカラーを調べると、何が起こっているかを確認できます。
これは次のことを示しています。
_+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+
| Expression | Evaluated As |
+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+
| DATEDIFF(MINUTE, 0, @TestValue) | Scalar Operator(datediff(minute,'1900-01-01 00:00:00.000',CONVERT_IMPLICIT(datetime,[@TestValue],0))) |
| DATEDIFF_BIG(MINUTE, 0, @TestValue) | Scalar Operator(datediff_big(minute,'1900-01-01 00:00:00.000',CONVERT_IMPLICIT(datetime,[@TestValue],0))) |
| DATEDIFF(MINUTE, '1/1/1900', @TestValue) | Scalar Operator(datediff(minute,'1900-01-01 00:00:00.0000000 +00:00',CONVERT_IMPLICIT(datetimeoffset(7),[@TestValue],0))) |
| DATEDIFF(MINUTE, CAST(0 AS DATETIME), @TestValue) | Scalar Operator(datediff(minute,'1900-01-01 00:00:00.000 +00:00',CONVERT_IMPLICIT(datetimeoffset(7),[@TestValue],0))) |
| DATEDIFF(MINUTE, CAST('1900-01-01' AS DATETIME2), @TestValue) | Scalar Operator(datediff(minute,'1900-01-01 00:00:00.0000000 +00:00',CONVERT_IMPLICIT(datetimeoffset(7),[@TestValue],0))) |
| DATEDIFF(MINUTE, 0, TRY_CAST(@TestValue AS DATETIME)) | Scalar Operator(datediff(minute,'1900-01-01 00:00:00.000',TRY_CAST([@TestValue] AS datetime))) |
+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+
_
この関数に_0
_を渡すと、常に暗黙的にdatetime
にキャストされます。
int
をdatetime
にキャストすると、_1900-01-01 + <int> days
_が返されるため、_1900-01-01
_が返されます。
あなたにとっての問題は、番目パラメータのデータ型が何にキャストされるかです。 _@TestValue
_は_datetime2
_の-整数を渡すと、両側が暗黙的にdatetime
にキャストされます。
_'0001-01-01 10:30:00.0000000'
_はdatetime
の範囲外なので、エラーが発生します。
それが成功するとき、パラメータは両方ともdatetimeoffset(7)
にキャストされます