SQL getdate() - 在一个语句中不相同

SQL getdate() - not the same in one statement

getDate() 语句总是 return 在一条语句中的任何地方具有相同的值。

但是,在一个 SQL Server 2017 中,我发现情况并非如此。

要进行设置,请创建一个 table 并将两行放入其中:

CREATE TABLE Test 
(
    TestDate datetime2(0) NULL,
    OtherValue varchar(5) NULL
) 

INSERT INTO Test (OtherValue) VALUES ('x')
INSERT INTO Test (OtherValue) VALUES ('x')

然后运行这个查询次数:

SELECT  
    CASE 
       WHEN GETDATE() < COALESCE(TestDate, GETDATE()) 
          THEN 'less'
       WHEN GETDATE() > COALESCE(TestDate, GETDATE()) 
          THEN 'greater'
       ELSE 'same' 
    END [Compare]
FROM 
    Test

两行始终 return 匹配结果。

当我在 SQL Server 2008 R2 (v10.50) 和其他 SQL Server 2017 机器上执行此操作时,结果总是 'same'.

但是,在我的一个 SQL Server 2017 实例上,它在 'same'、'less' 和 'greater' 之间随机变化:

为什么会这样?是否有可能导致此问题的服务器设置?

编辑:

使用 SYSDATETIME 代替 GETDATE 在 'bad' 服务器上按预期工作,始终 returning 'same'.

编辑 #2:

如果我在定义为 DATETIME 的列上测试 GETDATE(这是 GETDATE() 生成的内容),那么它会按预期工作。所以它似乎与DATETIMEDATETIME2之间的转换有关。

原来 getdate 的行为从 SQL 2000 年更改为 SQL 2005 年。

参见 对旧行为的解释:

In practice, GETDATE() is only evaluated once for each expression where it is used -- at execution time rather than compile time. However, Microsoft puts rand() and getdate() into a special category, called non-deterministic runtime constant functions.

following discussion:

In SQL 2000 if you did something like this

INSERT INTO tbl (fields, LOADDATE) SELECT fields, GETDATE() FROM tblb

you would get the same date/time for all records inserted.

This same command In SQL 2005, reruns GETDATE() for every single record selected from tblb and gives you potentially unique values for each record. Also causes HUGE performance problems if you are inserting say, 17 million rows at a time.

This has caused me many a headache, as we use this code to do batch date/times in many tables. This was a very simple way to back out a "batch" of transactions, because everything had the same date/time. Now in 2005, that is not true.

这个问题很有趣。

您示例中的行为可以用以下方式解释:

  1. 自 SQL Server 2016 以来,日期时间舍入已更改。简而言之:自 2016 SQL 服务器以来,在比较和与原始值执行比较之前,值不会四舍五入。 2016之前SQL服务器,取整后比较
  2. 默认情况下,比较 datetime 和 datetime2 执行将 datetime 转换为 datetime2(7)。你可以在执行计划中看到。
  3. 以 3 结尾的日期时间变量 - 例如 .003 - 在 .0033333 中转换。 007 在 .0066667 中转换。
  4. 最有趣的部分:纳秒。在比较期间 SQL 服务器在小数部分使用 8(或更多!)位数字。我只是举两个例子来解释。
DECLARE @DateTime datetime = '2016-01-01T00:00:00.003';
DECLARE @DateTime2 datetime2(7) = @DateTime;

select    datepart(NANOSECOND,@DateTime)      as  "DateTimeRes",
      datepart(nanosecond,@DateTime2)     as  "DateTime2Res"
go

DECLARE @DateTime datetime = '2016-01-01T00:00:00.007';
DECLARE @DateTime2 datetime2(7) = @DateTime;

select    datepart(NANOSECOND,@DateTime)      as  "DateTimeRes",
      datepart(nanosecond,@DateTime2)     as  "DateTime2Res"

结果:

+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
|     3333333 |      3333300 |
+-------------+--------------+

+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
|     6666666 |      6666670 |
+-------------+--------------+

我全部摘自 this 文章。

另外,SO上也有类似的

我相信此行为与您的服务器性能(虚拟机等)无关。 祝你好运!