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

时间:2015-03-24 16:32:49

标签: sql-server database coercion

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

这是有问题的查询的相关部分的摘录,具有固定值。第一个值代表"今天"在我们的查询中,并使用相同的数据类型设置了显式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服务器实例上有两个不同的数据库。

其中一个返回零行,正如您所期望的那样。

服务器1返回关于' 1/1/0001'的日期范围的错误:

  

Msg 242,Level 16,State 3,Line 1
  将varchar数据类型转换为日期时间数据类型会导致超出范围的值。

服务器2返回一个看起来正确的球场:

-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转换,因此这似乎是数据库1上的强制选择。

似乎数据库2使用不同的强制成功并正确地执行了约会数。

因为这两个数据库都在同一个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)

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

为什么这两个数据库对于这个相同的查询表现不同?为什么选择的胁迫似乎不同?

编辑:

  • 将查询转换为ISO日期文字以避免格式化时出现任何歧义。仍然看到相同的行为。
  • 添加了DBCC USEROPTOINS检查dateformat,两者都是mdy

1 个答案:

答案 0 :(得分:0)

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

请参阅涉及新日期/时间类型的转化

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

感谢Tab Alleman提出的交叉建议。