Sql-Server-2016
DATEDIFF(MINUTE, 0, <Date>) 中的 0 實際上是什麼意思?
因此,我們的數據團隊尋求一些幫助來解決他們遇到的問題。我最終將其追踪到一些真正超出範圍的數據(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), <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
.鑄造 an
int
todatetime
返回1900-01-01 + <int> days
so1900-01-01
。您的問題是第三個參數的數據類型被轉換為什麼。
@TestValue
is ofdatetime2
- 當你傳遞一個整數時,雙方都被隱式轉換為datetime
.
'0001-01-01 10:30:00.0000000'``datetime
因此錯誤超出範圍。在它成功的時候,參數都被強制轉換為
datetimeoffset(7)