SQL 同一 SQL 实例上的数据库之间的 DATEDIFF 强制差异?

SQL DATEDIFF coercion differences between databases on same SQL instance?

我有一个数据强制之谜。我看到同一查询有两种不同的行为,我不明白为什么。

这是相关查询的相关部分的摘录,具有固定值。第一个值在我们的查询中表示 "today",并设置为具有显式 CAST 的相同数据类型:

-- edited to change dates to ISO 8601 literal format to avoid ambiguity
SELECT DATEDIFF(dd,CAST('2014-03-24' AS SmallDateTime),'0001-01-01')

ISO 8601 日期文字格式引用:https://msdn.microsoft.com/en-us/library/ms187819.aspx

我们在同一个 SQL 服务器实例上有两个不同的数据库。

其中一个 returns 零行,如您所料。

服务器一 returns 关于“1/1/0001”的日期范围的错误:

Msg 242, Level 16, State 3, Line 1
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

服务器二 returns 一个看起来大致正确的值:

-735315

有问题的日期几乎可以肯定是“1/1/0001”,它失败了,正如我预期的默认日期时间,因为它低于 1753 年 1 月 1 日的最小 SQL 日期时间(https://msdn.microsoft.com/en-us/library/ms187819.aspx).

根据 datediff (https://msdn.microsoft.com/en-US/library/ms189794(v=SQL.105).aspx) 的 MSDN 页面,它可以接受以下值:

 startdate is an expression that can be resolved to a time, date, smalldatetime, datetime, datetime2, or datetimeoffset

每个服务器的施法结果在服务器之间是相同的,列于此处:

SELECT CAST('0001-01-01' As time) -- works: 00:00:00.0000000
SELECT CAST('0001-01-01' As date) -- works: 0001-01-01
SELECT CAST('0001-01-01' As smalldatetime) -- error: The conversion of a varchar data type to a smalldatetime data type resulted in an out-of-range value.
SELECT CAST('0001-01-01' As DateTime) -- error: The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
SELECT CAST('0001-01-01' As datetime2) -- works: 0001-01-01 00:00:00.0000000
SELECT CAST('0001-01-01' As datetimeoffset) -- works: 0001-01-01 00:00:00.0000000 +00:00

该错误明确指出失败的 DateTime 转换,因此这似乎是对数据库一的强制选择。

似乎数据库二使用了不同的强制转换,成功并正确地进行了 datediff 数学运算。

因为这两个数据库都在同一个 SQL 实例上,所以我排除了实例设置。

以下是我们想检查的一些数据库设置,它们在两个数据库之间看起来也相同(已在 SQL Server Management Studio 中检查):

数据库整理(应该是每台服务器,但为清楚起见包括在内):

(database) > Right Click > Properties > General > Maintenance > Collation
Database one: SQL_Latin1_General_CP1_CI_AS
Database two: SQL_Latin1_General_CP1_CI_AS

启用日期关联优化:

(database) > Right Click > Properties > Options > Misc. > Date Correlation Optimization Enabled
Database one: False
Database two: False

两位数年份截止值:

(database) > Right Click > Properties > Options > Containment > Two Digit Year Cutoff
Database one: 2049
Database two: 2049

用户选项日期格式

DBCC USEROPTIONS
Database one, dateformat: mdy
Database two, dateformat: mdy
(other settings appear identical)

我很乐意提供其他设置,或测试查询结果,让我知道您希望看到什么。

为什么两个数据库对于这个相同的查询表现不同?为什么看起来选择的强制不同?

编辑:

https://dba.stackexchange.com/questions/96101/sql-datediff-coercion-differences-between-databases-on-same-sql-instance

正如 Aaron Bertrand 在 DBA 堆栈交换站点上的回答,这植根于兼容性级别。

SELECT compatibility_level
FROM sys.databases WHERE name = 'FirstDatabase'

90

VS

SELECT compatibility_level
FROM sys.databases WHERE name = 'SecondDatabase'

110

Aaron 对这个问题的原因写得很好: https://dba.stackexchange.com/questions/44908/what-is-the-actual-behavior-of-compatibility-level-80

查看涉及新 date/time 类型的转化

更高的兼容性级别可能意味着 DateDiff 使用 DateTime2 或其他 'wider' 数据类型并且可以工作。在90或以下,它可能使用旧的DateTime,因此存在转换错误。

感谢 Tab Alleman 提出跨越 post 的建议。