Sql-Server-2016

DATEDIFF(MINUTE, 0, <Date>) 中的 0 實際上是什麼意思?

  • August 2, 2019

因此,我們的數據團隊尋求一些幫助來解決他們遇到的問題。我最終將其追踪到一些真正超出範圍的數據(1/1/0001)和他們正在使用的 DATEDIFF 函式。雖然我已經解決了他們的問題,但實際上我並不知道 0 在他們使用時會變成什麼。

我最初認為它更接近整數溢出而不是真正的轉換錯誤,但事實並非如此。我在帶有 DATEDIFF_BIG 和相同錯誤的 SQL 2016 框中嘗試了它。我在下面為你們提供了一個範例,以及哪些有效,哪些無效。

/** 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 的所有情況下都不起作用,還有什麼替代方法?

我們決定做什麼

因此,我開始建議我的團隊執行以下操作,因為您在很多 datemath 範例(每月的第一天等)中看到 0。因此,我建議您將 0 顯式轉換為 datetime,然後繼續。這將在仍然工作時避免錯誤。所以:

DATEDIFF(MINUTE, CAST(DATETIME, 0), &lt;Date&gt;)

您可以通過將表達式添加到帶有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.

鑄造 an inttodatetime返回1900-01-01 + &lt;int&gt; daysso 1900-01-01

您的問題是第三個參數的數據類型被轉換為什麼。@TestValueis of datetime2- 當你傳遞一個整數時,雙方都被隱式轉換為datetime.

'0001-01-01 10:30:00.0000000'``datetime因此錯誤超出範圍。

在它成功的時候,參數都被強制轉換為datetimeoffset(7)

引用自:https://dba.stackexchange.com/questions/208741