在一个select语句中嵌套With子句

时间:2014-05-19 09:46:41

标签: sql sql-server common-table-expression

我使用Common Table Expressions进行递归查询,获取开始日期和结束日期之间的日期范围

WITH T(date) AS (
SELECT @StartDate UNION ALL
SELECT DateAdd(day,1,T.date)   FROM T WHERE datediff(dd,T.date , @EndDate)>0 )
SELECT date FROM T OPTION (MAXRECURSION 32767))

有没有办法让我在没有创建临时表的情况下将其嵌套在另一个select语句中?

我正在寻找像这样的声明

select * from (WITH T(date) AS (
    SELECT @StartDate UNION ALL
    SELECT DateAdd(day,1,T.date)   FROM T WHERE datediff(dd,T.date , @EndDate)>0 )
    SELECT date FROM T OPTION (MAXRECURSION 32767)))
join 
    (select * from SomeTable where MyDate between @StartDate and @EndDate)
on //Some condition

我已经在SQL Server中尝试了这个,并且有一个

  

WITH WITH

附近的语法不正确

错误被抛出。

根据定义,CTE仅存在于查询范围内。那么,是否有必要使用临时表来存储CTE的结果,或者上述情况是否也有效?

2 个答案:

答案 0 :(得分:5)

您可以使用逗号分隔多个CTE,例如:

WITH T(date) AS 
(
    SELECT @StartDate 
    UNION ALL
    SELECT DateAdd(day,1,T.date)  
    FROM T
    WHERE datediff(dd,T.date , @EndDate)>0 

), T2 AS
(
    SELECT date 
    FROM T 
    OPTION (MAXRECURSION 32767)
)
select * from t2
join 
    (select * from SomeTable where MyDate between @StartDate and @EndDate)
on //Some condition

对于它的价值,使用递归CTE生成日期列表并不是最好的方法。最好的方法是拥有static calendar table,如果失败了,您可以动态生成一组日期,如下所示:

SELECT  TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
        Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @StartDate)
FROM    sys.all_objects a
        CROSS JOIN sys.all_objects b;

这比循环日期更有效。有关更多信息,请参阅:

答案 1 :(得分:0)

首先创建CTE,然后从中进行选择。

;WITH T(date) AS (
    SELECT @StartDate UNION ALL
    SELECT DateAdd(day,1,T.date)   FROM T WHERE datediff(dd,T.date , @EndDate)>0 
)
select * from T
join 
    (select * from SomeTable where MyDate between @StartDate and @EndDate) v
on //Some condition
OPTION (MAXRECURSION 32767)

如果您尝试创建日期范围,这可能会有所帮助:How to create a list of dates from a daterange without using a CTE