SQL意外舍入DateTime2结果

时间:2019-07-12 11:49:16

标签: sql sql-server

我们的程序中有一条update命令,该命令将比较where子句中的所有字段,以进行一致性检查(如果其中一个字段不匹配,则在获取数据期间会发生一些变化,实际上正在运行更新)

我对其中一个字段(DateTime类型)感到麻烦。但是,实际的Update命令使用的是Datetime2类型,因此我遇到了问题。

我们使此代码在多个站点上运行了很多年,并且没有出现问题,但是,当比较这两个站点时,一个站点开始表现奇怪。

由于某种原因,在将类型为Datetime的类型转换为Datetime2时,它没有明显的原因将查询向下舍入。我检查了多个不同的数据库(甚至在同一台服务器和其他服务器上),但没有发现相同的问题

我以以下脚本为例

declare @datetime datetime
set @datetime = '2016-07-11 13:50:11.957'

select CONVERT(datetime2,@datetime)`

在问题服务器上,这给了我以下结果

2016-07-11 13:50:11.9566667

在其他服务器上

2016-07-11 13:50:11.9570000

我看不出为什么从Datetime转换为datetime2会决定起飞时间吗?某处是否有数据库设置导致了这种情况?

1 个答案:

答案 0 :(得分:4)

SQL服务器处理从datetimedatetime2的转换方式(我记得在2014年是 )。这是有意记录的(将找到链接)。

较新的版本用datetime更恰当地表示datetime2,并显示精确到1/300秒的值,而不是0.0000.003或{{1} }秒。

编辑:更正,此更改是在SQL Server 2016中进行的。Breaking Changes in SQL Server 2016 (13.x)

  

在数据库兼容级别130下,来自的隐式转换   datetime到datetime2数据类型通过记帐显示出更高的准确性   小数毫秒,导致不同的转换   价值观。每当混合使用显式强制转换为datetime2数据类型   存在datetime和datetime2数据类型之间的比较方案。   有关更多信息,请参见此Microsoft Support Article

编辑:下面将对以下OP进行评论:“仍然没有解释为什么SQL Server认为删除时间而不是仅仅添加000来”更准确“。。事实并非如此,带有新版本的SQL Server不会随时删除(或添加),而这恰恰是新转换规则的重点。因为旧的转换确实消除/增加了时间。

常见的误解是0.007精确到1/1000秒,因为它显示3个小数位,例如datetime。就像我说的那样,这是一个误解,而且是错误的。 2016-07-11 13:50:11.957的精确度是 1/300 ,这就是为什么datetime中的最后一位是datetime0.000和{ {1}}。这是因为不以0结尾的值是真正 0.0030.007

这就是为什么在新版本中,将0.003333333~之类的值转换为0.00666666~时显示为datetime2(7)的原因,因为这更加准确。实际上,SQL Server的版本将2016-07-11 13:50:11.957之类的值四舍五入为2016-07-11 13:50:11.9566667,这意味着它已将该值添加 2016-07-11 13:50:11.9566666~。对于2016-07-11 13:50:11.9570000之类的值,转换将从该值中删除 0.0003333~,以生成2019-07-12 14:13:12.1233333~

这就是为什么较新版本赋予不同值的原因。它们更准确

另一项编辑:David Dubois提出的观点是,对于下面的SQL(或类似的SQL),他们希望0.0003333~语句出现在SQL Server 2016+中:

2019-07-12 14:13:12.1230000

但是,如果尝试此操作,则不会。正如我在评论中提到的那样,以上引用中实际上涵盖了这一点,但要重申特定的句子:

  

每当混合使用显式强制转换为datetime2数据类型   存在datetime和datetime2数据类型之间的比较方案。

如果您按照文档说明将上述内容更改为显式转换,则查询将按您期望的方式工作:

PRINT

关于SQL Server 2014或更低版本的说明,对于隐式和显式转换,以上内容均会返回DECLARE @dt2 datetime2, @dt datetime; SET @dt = '2016-07-11T13:50:11.957'; SET @dt2 = @dt; IF @dt2 = @dt PRINT 'The Same (Implicit)'; --Implicit is important 语句。