【发布时间】:2018-08-03 12:37:23
【问题描述】:
我了解通常将当前日期声明为变量是有用的:
DECLARE @CurrentDate as DateTime
SET @CurrentDate = Getdate()
我的理解是,这会对当前日期/时间进行一次采样并将其记录为静态变量。这有助于确保“当前时间”在查询期间保持不变,并且还可以避免重复使用比获取变量值更昂贵的 Getdate()。
我的问题是....在递归 WITH 子句的情况下是否需要这样做,该子句似乎是一次获取日期?
例如,考虑以下代码:
WITH CalendarSequence as(
SELECT Getdate() as RollingDate
UNION ALL
SELECT DateAdd(month, -1, RollingDate) as RollingDate
FROM CalendarSequence
WHERE DateAdd(month, -1, RollingDate) > Convert(date, '2016-01-01')
)
SELECT
Year(CalendarSequence.RollingDate)*100+Month(CalendarSequence.RollingDate) as MissingYearMonth
FROM CalendarSequence
LEFT OUTER JOIN TableName
ON Year(CalendarSequence.RollingDate)*100+Month(CalendarSequence.RollingDate) = TableName.YearMonthField
WHERE TableName.YearMonthField is NULL
此查询生成一个临时日期表,并将其与任意表进行比较,以突出显示没有活动/数据的各个月份。
就这段特定的代码而言,Getdate() 是否被多次使用并不重要(除非在查询执行期间月份发生了变化!)但对于类似的查询而言,这并非普遍适用。我提出这个问题的部分动机是为了更好地了解 WITH 函数正在做什么以及它是否有任何令人惊讶的行为。
【问题讨论】:
-
不,但您可能应该使用日历表。一个完整的索引表,例如 50 年,其中包含年、月、日、ISO 和非 ISO 周数、标签、各种日期表示等字段,而不是每次都重建它不会占用很多空间。加入它会比使用生成的日期范围快很多
-
这是一个答案,但是,我认为它不能完全解决您的问题,所以我在评论。通常,您不需要将
GETDATE分配给变量。如果这样做,很可能在整个批次中对GETDATE使用相同的值。例如,如果您在一个批次中有多个语句,则这 2 个语句可能具有不同的GETDATE值。如果它们需要相同,则首先将值分配给变量,然后引用该变量。如果他们不需要(或者没关系),那么你可以简单地使用GETDATE。 -
在查询中,
GETDATE()对于所有行始终只有一个值,因此无论您的WITH处理多少行,或者在处理过程中时间是否发生变化,都无关紧要。 (对于一个更有说服力的例子,试试SELECT SYSUTCDATETIME() FROM hugetable。)这通常适用于 T-SQL 函数,即使是像RAND()这样的非确定性函数,但值得注意的例外是NEWSEQUENTIALID()和NEWID(),它们确实适用于-row 值(以及明显设计为每行更改的函数,如ROW_NUMBER()和NEXT VALUE FOR)。说了这么多……似乎没有记录。 -
虽然 GetDate() 由于优化而出现固定,并且正如有人说 newid() 不固定,我确实在这里看到一个查询 newid() 出现固定 - 所以如果你想保证 getdate( ) 是固定的,使用变量,它肯定只能“一样好或更好”,永远不会更糟
-
啊,这里有一些more 在这个问题上应该真正说服你使用一个变量:多个独立的
GETDATE()s 不保证在其中具有相同的值相同的查询,优化器不会统一这些值。我很确定您仍然无法仅使用单个GETDATE()来显示差异,因为我想不出一种方法可以使优化器生成一个计划,在该计划中它的评估就像它在不同的列中一样,但依赖它似乎很不明智。
标签: sql-server tsql