返回连续日期的临时表
Posted
技术标签:
【中文标题】返回连续日期的临时表【英文标题】:Return temp table of continuous dates 【发布时间】:2009-09-08 17:54:39 【问题描述】:我需要创建一个返回连续日期表的函数。我会传入一个最小和最大日期。
我希望它可以这样调用:
SELECT * FROM GetDates('01/01/2009', '12/31/2009')
我目前有一个执行此操作的存储过程,但要求发生了变化,现在我需要在联合中包含返回的数据:
with mycte as
(
select cast(@minDate as datetime) DateValue
union all
select DateValue + 1
from mycte
where DateValue + 1 <= @maxDate
)
select DateValue
from mycte
option (maxrecursion 1000)
但是,问题是我需要将递归设置为大于 100。根据 Gail Erickson [MS] 在 eggheadcafe 上的帖子,目前不支持此功能。
如果不创建一个真正的(不是临时的)表,其中只有日期,有没有办法做到这一点?
我正在使用 SqlServer2005。
【问题讨论】:
可以将递归级别设置为高于 100 的值。如果我没记错的话,支持的最大级别是 2^15。 【参考方案1】:您最好的选择是实际拥有一个实际的日期表。即使在很长一段时间内也没有那么多,而且比从临时表或递归 ctes 即时实现它们要快得多。
【讨论】:
如果你不希望有一个日期表,一个中间解决方案是使用一个[较小的]数字表(比如从 0 到 1000)并使用类似 select cast(@ minDate as datetime) + Val from tblNumbers where val 谢谢,我决定使用物理表,使用一列仅存储日期的表似乎是个坏主意。 这不是一个坏主意。它违背了程序员通常的面向算法的思维方式,仅此而已。实际上,许多人建议使用只有数字的表格,从 0 到 1 百万。或类似的,用于与您类似的联接和查询。【参考方案2】:如果您选择(或需要)使用临时表而不是永久表,则可以这样做:
CREATE FUNCTION dbo.DateList
(
@MinDate datetime
,@MaxDate datetime
)
RETURNS TABLE
RETURN WITH
Pass0 as (select 1 as C union all select 1), --2 rows
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows
Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows
Tally as (select row_number() over(order by C) as Number from Pass4)
select dateadd(dd, Number - 1, @MinDate) DateValue
from Tally
where Number < datediff(dd, @MindAte, @MaxDate) + 2
去
还有一个测试电话:
DECLARE
@MinDate datetime
,@MaxDate datetime
SET @MinDate = 'Jan 1, 2009'
SET @MaxDate = 'Dec 31, 2009'
SELECT *
from dbo.DateList(@MinDate, @MaxDate)
奇怪——这是今天第三篇涉及 Tally 表的 SO 帖子。一定是发生了一些奇怪的太阳黑子活动。以下是链接:
count number of rows that occur for each date in column date range.What is the best way to create and populate a numbers table?
【讨论】:
【参考方案3】:类似这样的:
CREATE FUNCTION GetDates(@StartDate DateTime, @EndDate DateTime)
RETURNS @Dates Table ( aDate DateTime Primary Key Not Null)
AS
BEGIN
Declare @ThisDate DateTime Set @ThisDate = @StartDate
While @ThisDate < @EndDate begin
Insert @Dates (aDate) Values(@THisDate)
Set @ThisDate = @ThisDate + 1
End
RETURN
END
GO
确保@EndDate 在@startdate 之后...添加输入参数检查以确保,否则如果您向后传递日期,它可能会永远运行
【讨论】:
循环会变慢。 CTE会是更好的选择以上是关于返回连续日期的临时表的主要内容,如果未能解决你的问题,请参考以下文章