我们的程序中有一条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会决定起飞时间吗?某处是否有数据库设置导致了这种情况?
答案 0 :(得分:4)
SQL服务器处理从datetime
到datetime2
的转换方式(我记得在2014年是 )。这是有意记录的(将找到链接)。
较新的版本用datetime
更恰当地表示datetime2
,并显示精确到1/300秒的值,而不是0.000
,0.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
中的最后一位是datetime
,0.000
和{ {1}}。这是因为不以0结尾的值是真正 0.003
和0.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
语句。