2010-06-18 49 views
3

我正在尝试编写使用CTE的动态查询。但我面临的问题 - 见下文 这是一个简化的情况使用CTE的SQL Server 2008动态查询

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) 

这不工作 - 我得到的错误是 无效的对象名称“月”

是否有实现的任何方式我想。如果我使用Temp表或表变量,它会起作用吗?

+0

您不能在cte中引用cte。 – websch01ar 2010-06-18 20:39:57

+0

为什么你需要'从月份选择COUNT(*)?为什么你需要一个'动态'查询? – van 2010-06-18 20:41:09

+0

如果我不把选择计数(*)它抱怨'未使用CTE'。我正在尝试创建Y轴上数月的数据透视查询。月数是可变的。所以我将不得不创建枢轴像枢轴(sum(fld)为col in(['jan-10'],['feb-10'] ...) – josephj1989 2010-06-18 20:54:23

回答

2

您的动态SQL无法引用months。一个CTE的范围是单个声明

with cte as (cte definiton) select from cte; 

如果你想重新使用CTE的结果或定义,你必须要么你想用的时候就重新定义了CTE(如。在@DynSql中)或将其结果实现为一个表@variable并重新使用表@variable。

+1

不,我尝试了一个表变量,但它看起来像你不能在动态SQL中使用表变量 – josephj1989 2010-06-18 20:55:50

+1

动态sql在不同的作用域中执行基本上是一个函数调用它不能引用当前上下文中的变量使用'exec sp_executesql @DynSql',@parameterName type',@ localTVP'作为参数传入要从当前作用域/上下文中使用的任何变量。 – 2010-06-18 21:10:23

+0

请参见http://msdn.microsoft.com/en-us/库/ bb510489。aspx为一个示例如何将一个本地表@variable传递给一个过程。 – 2010-06-18 21:12:49

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) 
+0

没有我的问题是不从cte中选择count(*),而是使用Dynamic Sql中的CTE。 – josephj1989 2010-06-18 20:57:25

+0

现在我看到你正在尝试使用Pivot()。利用您提供的数据,您将获得一个参考点。你想把它与什么比较?多一点信息,我可以使用cte。 – websch01ar 2010-06-18 20:59:32

+0

几乎完成了重写... – websch01ar 2010-06-18 22:10:33

3

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

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) 
+0

我已经试过这个。我需要使用数据透视表来显示整个页面的月度数据。我正在尝试创建一个跨Y轴数月的数据透视查询。月数是可变的。所以我将不得不创建枢轴,像pivot(sum(fld)for col in(['jan-10'],['feb-10'] ...)。因此,我必须创建月份列表一部分是动态查询。但是数据透视查询与CTE月份交叉连接。因此,我需要在动态SQL之外定义月CTE,并在其中添加月份。我试图将月份插入到表变量中并将它传递给sp_execsql,但它确实不接受表格变量 – josephj1989 2010-06-18 21:36:59

+0

是的,没有视图,你需要在动态SQL里面创建CTE,我不明白问题是什么,也许发布更多的问题和错误信息会有帮助。 – 2010-06-18 21:52:46

0

您不能使用CTE或@TableVariable在动态SQL,但你可以使用一个#TEMP表这一点。创建一个临时表,将数据存储在那里(你可以将你的CTE结果复制到临时表)并在动态查询中使用它。这是解决方案。