在查询字符串中引用表变量

gre*_*can 1 sql t-sql sql-server

我创建了一个temprary表变量,然后我需要进行调整:

Declare @TempTable TABLE(
Name varchar(150),
CloseDate Date, 
Revenue Float)

.... <add data to it> .....    

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(CloseDate) 
            FROM @TempTable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT  Name, ' + @cols + ' from 
                (select 
                    t.Name,
                    t.CloseDate,
                    t.Revenue
                from @TempTable as t
                ) x
            pivot 
                (SUM(Revenue)
                    for CloseDate in (' + @cols + ')
                ) p '

execute(@query)
Run Code Online (Sandbox Code Playgroud)

但是,我收到此错误:

Must declare the scalar variable "@TempTable".
Run Code Online (Sandbox Code Playgroud)

当我使用普通的SELECT测试@TempTable变量时它工作正常:

SELECT * from @TempTable
Run Code Online (Sandbox Code Playgroud)

如何在查询字符串中成功引用变量?

Dav*_*vid 5

不幸的是,当您使用execute和sp_executesql时,它们在自己的上下文中运行,因此它们不能引用在动态SQL范围之外定义的表变量对象.

在这种情况下,我倾向于创建临时表,并在tempdb中创建的临时表的名称中嵌入GUID.这确保了表名对于同时操作是唯一的,然后我将该guid放在创建的动态SQL中.

性能方面,它稍微慢但仍然很快,但是否对你来说是一个问题取决于它将执行的次数和频率.

在对此答案的评论中与Damien进行了一些讨论之后,我们确定在执行动态SQL时可以使用本地临时表(单个哈希标签).

因此,如果将声明表变量更改为CREATE TABLE #TempTable并更改动态SQL中的引用,则此方法应该适合您.

我对使用临时表的唯一关注是如果你的调用代码使用某种形式的连接池,那么对象的持久性就不像这里的情况那样.

但是,作为一般的自我偏执的自我练习,我喜欢在创建表之前和语句末尾抛出其中一个来清理对象.

IF OBJECT_ID(N'tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable

CREATE TABLE #TempTable (Value VARCHAR(50));
Run Code Online (Sandbox Code Playgroud)