是否可以使用CTE递归编写以下查询?

时间:2016-08-29 09:29:36

标签: sql sql-server tsql

create table #temp (date date)
declare @X date
set @X = '2016-7-01'
declare @Y date 
set @Y = cast (getdate() as date)
while(@X<=@Y) 
begin
if (datename(WEEKDAY,@X) = 'Sunday')
insert into #temp values (@X)
set @X = cast(((cast(@X as datetime))+1)as date)
continue
end
select * from #temp
drop table #temp

是否可以使用CTE递归编写上述查询?

3 个答案:

答案 0 :(得分:1)

您可以使用CTE创建数字表。然后,您可以使用数字表来获取日期:

Declare @Startdate Datetime = '2016-07-01'
Declare @EndDate Datetime = '2016-08-29'

;with
 N0 as (SELECT 1 as n UNION ALL SELECT 1)
,N1 as (SELECT 1 as n FROM N0 t1, N0 t2)
,N2 as (SELECT 1 as n FROM N1 t1, N1 t2)
,N3 as (SELECT 1 as n FROM N2 t1, N2 t2)
,N4 as (SELECT 1 as n FROM N3 t1, N3 t2)
,nums as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as num FROM N4)
SELECT DATEADD(day,num-1,@startdate) as thedate
FROM nums
WHERE num <= DATEDIFF(day,@startdate,@enddate) + 1
and datename(WEEKDAY, DATEADD(day,num-1,@startdate)) = 'Sunday'

每个表格(N0nums)有效地将前一个“表格”中的行数相乘,因此您最终会在nums中找到65,536行数字(您可以执行此操作)通过根据需要添加或删除表NX来减少或更多。然后,使用数字表将天数添加到开始日期(SELECT DATEADD(day,num-1,@startdate) as thedate),其中返回的日期位于您的日期范围内,weekday为星期日。

此外,由于nums中的数字从1开始,我们在选择中使用nums-1,以避免跳过我们系列中的第一个日期,从而有效地为我们DATEADD(day, 0, @startdate)在我们的第一排。

答案 1 :(得分:0)

你可以尝试这里解释的内容:http://blog.sqlauthority.com/2009/12/29/sql-server-get-date-of-all-weekdays-or-weekends-of-the-year/

DECLARE @StartDate DATETIME
DECALRE @EndDate DATETIME

SET @StartDate = '2016-07-01'
SET @EndDate = GETDATE()

;WITH cte AS (

    SELECT 
        1 AS DayID,
        @StartDate AS FromDate,
        DATENAME(dw, @StartDate) AS Dayname

    UNION ALL

    SELECT 
        cte.DayID + 1 AS DayID,
        DATEADD(d, 1, cte.FromDate),
        DATENAME(dw, DATEADD(d, 1, cte.FromDate)) AS Dayname
    FROM cte
    WHERE DATEADD(d, 1, cte.FromDate) < @EndDate
)
SELECT FromDate AS Date, Dayname
FROM cte
WHERE Dayname IN ('Sunday')

我认为通过使用数字表和7倍(取决于您需要获得多少日期,可能预先计算第一个星期日),这是一种更有效的方法从你的开始日期开始,然后从数字表中加入所有数字7的数字),但上面的效果也很好。

答案 2 :(得分:0)

;with cte
as
(
select getdate() as datee
union all
select dateadd(day,1,datee)
from cte
where datediff(day,getdate(),datee)<100
)
select * from cte
where datename(WEEKDAY,datee) = 'Sunday'

你也会达到最大递归限制,以避免..使用类似下面的东西..

option ( MaxRecursion 0 )

如果我不受使用递归cte的限制,我会使用数字表来解决这个问题,这也比Recursive cte快..

select 
dateadd(day,n,getdate()) as datee 
from numbers
where n<100 and datename(weekday,dateadd(day,n,getdate()))='sunday'

要了解您需要数字表的原因,请查看此链接.. https://dba.stackexchange.com/questions/11506/why-are-numbers-tables-invaluable