Sql server 如果在同一语句中使用两次,GETUTCDATE()是否返回相同的值?

Sql server 如果在同一语句中使用两次,GETUTCDATE()是否返回相同的值?,sql-server,Sql Server,我有一个触发器,每当输入值时,它会自动将给定条目的CreationDate和ModifiedDate设置为当前UTC时间。(此后CreationDate将保持不变,而ModifiedDate将通过另一个触发器在每次更新时更新) 我想确保插入的和从未更新的项目对于CreationDate和ModifiedDate具有完全相同的值,因此我使用了如下变量: DECLARE @currentTime DATETIME SELECT @currentTime = GETUTCDATE() UPDATE d

我有一个触发器,每当输入值时,它会自动将给定条目的CreationDate和ModifiedDate设置为当前UTC时间。(此后CreationDate将保持不变,而ModifiedDate将通过另一个触发器在每次更新时更新)

我想确保插入的和从未更新的项目对于CreationDate和ModifiedDate具有完全相同的值,因此我使用了如下变量:

DECLARE @currentTime DATETIME
SELECT @currentTime = GETUTCDATE()
UPDATE dbo.MyTable SET CreationDate = @currentTime, ModifiedDate = @currentTime
    ...
在我的命令式编程思想中,我假设这可以防止
GETUTCDATE()
被调用两次,并可能产生稍微不同的结果。这真的有必要吗?如果不是,这会更贵、更便宜,还是与下面的代码完全相同

UPDATE dbo.MyTable SET CreationDate = GETUTCDATE(), ModifiedDate = GETUTCDATE()
    ...

它将是相同的值

GETDATE和GETUTCDATE是一些函数,每个查询只计算一次:而不是该查询中的每行或每列。优化程序将确保它们相同,因为它会同时更新值

另一个选项是定义默认约束,这样您就可以做到这一点,而不用担心它

UPDATE dbo.MyTable
SET CreationDate = DEFAULT, ModifiedDate = DEFAULT, ...
...
我有一些表具有类似的列和默认约束,从来没有出现过问题。这也意味着我永远不必考虑在代码中使用什么函数

编辑:

我可能错了:

或者我可能是对的:

第条:


Edit2:我明显错了:参见StriplingWarrior的自我回答。它是按列计算的(不是按行计算,也不是按查询计算)

将GETUTCDATE()保留在变量中是一个更好的选择,因为它可以确保CreationDate和ModifiedDate保持不变。但是,我调用了每个查询的时间数,它们都返回了相同的值,因此在我看来,每个查询的GETUTCDATE()值保持不变。

多亏了gbn提供的链接,我相信:

与rand()一样,它对每列计算一次,但对所有行计算一次仍然相同。 ... 查看实际执行计划中的ComputeScalar运算符属性,您将看到GetDate()计算了两次

我检查过了,在SQLServer2008中,这种情况似乎仍然以相同的方式发生:
GetUtcDate()
在执行计划中被计算两次。它不会在每行中产生不同的结果,但如果时间恰好结束,它可能会在每列中产生不同的结果

编辑 我可以证明这种行为!试试这个:

select GETUTCDATE(), RAND(), RAND(), ...[~3000 RAND()s]..., RAND(), GETUTCDATE()
from [TableOfYourChoice]

在我的实验中,我在第一列和最后一列分别以
2011-05-17 20:47:34.247和
2011-05-17 20:47:34.250结束,结果显示,由于对GETUTCDATE()的第一次和第二次调用之间的所有
RAND()
s的求值结果相差三毫秒.

基于SQL Server 2008中的大量实验,我相信以下描述是正确的:

在单个SELECT、INSERT或UPDATE查询中,date和time函数的每个外观都将在所有行和列中显示的任何位置返回相同的值,包括列默认值

两个不同的日期和时间函数(例如GETUTCDATE()和GETDATE())可能会相互返回不同的时间(即使在调整时区或其他任何时间之后)

单个批次中的多个查询可能返回不同的值

SELECT GETUTCDATE(), GETUTCDATE() -- These will be the same

SELECT GETUTCDATE()  --  These may
SELECT GETUTCDATE()  --  be different
这种行为在任何地方都没有记录,使用变量可以清楚地表明意图,因此我可能不会依赖这种行为,除非避免这种依赖是一个主要负担

DECLARE @Counter INT = 1

WHILE (1 = (SELECT 1 WHERE GETUTCDATE()  = GETUTCDATE()))
SET @Counter = @Counter+1

SELECT @Counter /*Returns almost immediately with a number in the 000s for me.*/
为了证明这一点,在
列表中选择
时也会发生

DECLARE @T TABLE 
(
rownum INT IDENTITY(1,1) PRIMARY KEY,
d1 datetime,
d2 datetime
)

WHILE (NOT EXISTS(SELECT * FROM @T WHERE d1 <> d2))
    BEGIN
    DELETE FROM @T
    INSERT INTO @T 
    SELECT GETUTCDATE(),GETUTCDATE()
    END

SELECT * FROM @T

你知道这是否是官方记录的吗?我不想依赖这种行为,除非它是一个记录在案的功能,而且我在过去也没有成功地找到这样的东西。@Jeffrey L Whitledge:它在很多地方间接记录了每个查询的函数求值,而不是每行的函数求值。包括这里等等。我会检查一下的。+1,谢谢你的链接。你说得对,它不是按行计算的,但从我收集的数据来看,它似乎是按列计算一次,但它发生得太快了,可能99.99%的时间都是相同的。@StriplingWarrior-如果99.99%的时间都是相同的,并且你的逻辑取决于列是相同的,如果您的表中有一百万行,那么您将有100行错误!也许最好还是坚持使用一个变量。@Jeffrey L Whitledge:同意。这就是为什么我给了a+1,但没有把这个答案标记为正确。谢谢你花时间来测试这个,但这实际上是不正确的。见我的最新答案。同意。执行我答案中的代码也清楚地表明了这一点。这是一个非常简单的证明,它并不总是返回相同的值。
CREATE FUNCTION dbo.GETUTCDATE()
RETURNS DATETIME
WITH SCHEMABINDING
AS
BEGIN
RETURN GETUTCDATE()
END
GO

SELECT GETUTCDATE(),dbo.GETUTCDATE()
FROM master..spt_values