web-dev-qa-db-ja.com

DATEDIFF(MINUTE、0、<Date>)の0は実際にはどういう意味ですか?

したがって、私たちのデータチームは、彼らが抱えている問題を解決するための支援を求めました。最終的には、実際に範囲外のデータ(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>)
4
Jonathan Fite

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にキャストされます。

intdatetimeにキャストすると、_1900-01-01 + <int> days_が返されるため、_1900-01-01_が返されます。

あなたにとっての問題は、番目パラメータのデータ型が何にキャストされるかです。 _@TestValue_は_datetime2_の-整数を渡すと、両側が暗黙的にdatetimeにキャストされます。

_'0001-01-01 10:30:00.0000000'_はdatetimeの範囲外なので、エラーが発生します。

それが成功するとき、パラメータは両方ともdatetimeoffset(7)にキャストされます

7
Martin Smith