【发布时间】:2021-04-19 09:33:51
【问题描述】:
我在使用 Microsoft SQL Server 2016 (SP2-CU15) 时遇到了一个非常奇怪的行为:
select convert(datetime, max(TS) + 1.0/24) as A
from table;
收益2021-01-16 11:59:00.000
同时
select convert(datetime, max(TS) + 1.0/24) as A
, dateadd(hour, 1, max(TS)) as B
from table;
给我2021-01-16 11:58:59.943 用于A(和2021-01-16 11:59:00.000 用于B)。所以,在我看来,添加第二列会改变第一列的结果?!
我可以通过将 1.0 转换为 real 来强制两列版本工作,顺便说一句:convert(datetime, max(TS) + cast(1.0 as real)/24),但我可以不通过写 convert(datetime, max(TS) + cast(1.0 as float)/24) 来强制一列版本失败。
有什么想法吗?
谢谢!
亨德里克。
更新:根据要求,这是一个最小示例:
CREATE TABLE TestTS (TS FLOAT);
INSERT INTO TestTS (TS) VALUES (44210.4993055556);
SELECT convert(datetime, max(TS) + 1.0/24) as A
, dateadd(hour, 1, max(TS)) as B
from TestTS
如前所述,如果注释掉 B 列,A 的值会发生变化。
【问题讨论】:
-
DATEADD 没有副作用。发布一个可重现的示例:
CREATE TABLE命令,INSERT与实际值,SELECT与查询,期望和。实际的。价值观。数据错误或什至没有存储为日期的可能性要大得多。convert(datetime, max(TS) + 1.0/24)有什么意义? -
顺便说一句
1.0/24导致一个无理数:0,04166666666....。将数字添加到日期是一种仅适用于datetime的技巧 - 只有datetime可以被视为数字。浮点运算会导致精度问题,因此您必须假设添加小数值会总是导致结果不准确。请改用DATEADD -
DATEADD没有错。该错误首先使用max(TS) + 1.0/24 -
1.0/24返回0.041666所以这并没有保留很多小数位,这并不奇怪你在查看毫秒时会遇到问题 -0.041666 * 24 * 60 * 60 * 1000意味着只有3599942毫秒一天内。而不是3600000 -
至于这里的问题。我可以重现这个问题。当第二列存在与不存在时,它会将不同的值编译到计划中 i.stack.imgur.com/R9mEQ.png
标签: sql-server datetime casting dateadd