使用CTE的SQL Server 2008动态查询

时间:2010-06-18 20:34:54

标签: sql sql-server

我正在尝试编写一个使用CTE的动态查询。但我遇到了问题 - 见下文 这是一个简化的案例

declare @DynSql varchar(max)='';
declare @cnt as integer;
with months as (
select CAST('07/01/2010' as DATE) stdt
UNION ALL
SELECT DATEADD(MONTH,1,STDT) FROM months
WHERE DATEADD(MONTH,1,STDT)<CAST('06/30/2011' AS DATE)
)
select COUNT(*) from months
set @DynSql='select * from months'
exec (@DynSql)

这不起作用 - 我得到的错误是 无效的对象名称'Months'

有没有办法实现我想要的东西。如果我使用Temp表或表变量,它会起作用。

4 个答案:

答案 0 :(得分:3)

with关键字未声明可在以后的查询中引用的对象。它是选择查询的一部分。你的动态sql试图引用一个不存在的对象months。在定义dyanic查询的字符串中包含CTE。

declare @DynSql varchar(max)=''; 
set @DynSql=
'with months as ( 
    select CAST(''07/01/2010'' as DATE) stdt 
    UNION ALL 
    SELECT DATEADD(MONTH,1,STDT) FROM months 
    WHERE DATEADD(MONTH,1,STDT)<CAST(''06/30/2011'' AS DATE)) 
select * from months'
exec (@DynSql) 

但是,我没有看到你通过使SQL动态获得什么,因为SQL语句中的任何内容都不同。


如果你想要一个稍后可以引用的对象,你可以创建一个由动态查询和类似查询(多次)使用的视图(一次)。

create view months_v as 
    with months as (select CAST('07/01/2010' as DATE) stdt 
        UNION ALL 
        SELECT DATEADD(MONTH,1,STDT) FROM months 
        WHERE DATEADD(MONTH,1,STDT)<CAST('06/30/2011' AS DATE)) 
    select * from months;
go

declare @DynSql varchar(max)='';
set @DynSql='select * from months_v' 
exec (@DynSql) 

答案 1 :(得分:2)

您的动态SQL无法引用months。 CTE的范围是单个语句

with cte as (cte definiton) select from cte;

如果要重新使用CTE的结果或定义,则必须在每次要使用它时重新定义CTE(例如在@DynSql中)或将其结果实现到表@variable和重新使用表@variable。

答案 2 :(得分:0)

嗯,我得到了它的工作,但我不明白这个的范围...

declare @DynSql varchar(max)
declare @cnt as integer;
declare @stdt datetime;
Set @DynSql =''
Select @stdt = CAST('07/01/2010' as DATEtime);
with months as ( 
SELECT DATEADD(MONTH,1,@stdt) As [month] WHERE DATEADD(MONTH,1,@stdt)<CAST('06/30/2011' AS DATEtime) 
) 
select COUNT(*) from months 

现在修改我已移动信息:

declare @DynSql varchar(max)
declare @cnt as integer;
declare @stdt datetime;
Set @DynSql = 'With ctemonths  as ('
Select @stdt = CAST('07/01/2010' as DATEtime);
Set @cnt = 1;
while @cnt <= 11 --(Select DateDiff(mm, @stdt, '06/30/2011'))
Begin
    IF (@CNT =1)
        Set @DynSql = @DynSql + 'Select DATEADD(MONTH,' + Cast(@cnt as nvarchar(2)) + ',''' + Convert(varchar(10), @stdt, 103) + ''') As [month] '
    eLSE
        Set @DynSql = @DynSql + 'UNION Select DATEADD(MONTH,' + Cast(@cnt as nvarchar

(2)) + ',''' + Convert(varchar(10), @stdt, 103) + ''') As [month] '
Set @cnt = @cnt + 1

End;

Set @DynSql = @DynSql + ') Select * from ctemonths' -- PIVOT (max([month]) for [month] in ([month]))'

exec (@DynSql)

答案 3 :(得分:0)

您无法在动态sql中使用该CTE或@TableVariable,但您可以使用#Temp表。创建临时表,将数据存储在其中(您可以将CTE结果复制到临时表)并在动态查询中使用它。这就是解决方案。