我正在尝试编写一个使用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表或表变量,它会起作用。
答案 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结果复制到临时表)并在动态查询中使用它。这就是解决方案。