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

标签 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/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.

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

-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)

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

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

编辑:

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

最佳答案

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

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

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

90

对比

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 提出交叉发布的建议。

关于sql-server - 同一 SQL 实例上数据库之间的 SQL DATEDIFF 强制差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29238048/

相关文章:

javascript - JavaScript将 bool 值/单次标记后缀以限制事件

sql-server - SQL Server 内存中 oltp 事务快照隔离

mysql - 重新排序/重置自动增量主键

database - 使用 SHA1 key 避免 BigTable 或 HBase 中的热点

perl - 驼鹿胁迫和 build 者

javascript - 使用 valueOf 数学运算进行类型强制

sql-server - 在数据库中存储大量文件

sql-server - 基于列的相交在两个表上

sql - 查询以获取我的 SQL Server 中的事件查询列表

sql - 从不同的数据库postgresql复制表