在存储过程中使用带有 exec @sql 的临时表

Posted

技术标签:

【中文标题】在存储过程中使用带有 exec @sql 的临时表【英文标题】:Using temp table with exec @sql in stored procedure 【发布时间】:2013-11-02 13:04:28 【问题描述】:

我有一个存储过程,其中一部分如下: @DRange 是传入的 varchar 值

declare @sql varchar(max)
set @sql = 'select * into #tmpA from TableA where create_date >= getDate - ' + @DRange + '' and is_enabled = 1'

exec (@sql)

select * from #tmpA

问题是当我执行存储过程时,出现错误消息: 找不到对象“#tmpA”,因为它不存在或您没有权限。

是不能使用临时表并执行它还是我做错了什么?

【问题讨论】:

为什么要使用动态SQL?你不能有一个正常的查询select * into #tmpA from TableA where create_date >= getDate - @DRange and is_enabled = 1 吗?如果需要,可以将 @DRange 转换为不同的类型 因为我需要在查询中结合其他参数,例如数据库名称。 【参考方案1】:

#tmpA 在不同的范围内创建,因此在动态 SQL 之外不可见。您可以将最终的SELECT 作为动态SQL 的一部分。还有其他几件事:

Always use the schema prefix when creating/referencing objects Always use sp_executesql for dynamic SQL;在这种情况下,它允许您参数化 @DRange 值并避免 SQL 注入风险。 始终为 Unicode 字符串添加 N 前缀 - sp_executesql 需要 Unicode,但如果您在代码的其他区域对此感到懒惰,也会导致痛苦的隐式转换。
DECLARE @sql NVARCHAR(MAX);

SET @sql = N'select * into #tmpA from dbo.TableA 
    where create_date >= DATEADD(DAY, -@DRange, GETDATE())
    AND is_enabled = 1; SELECT * FROM #tmpA';

EXEC sp_executesql @sql, N'@DRange INT', @DRange;

当然,如果您所做的只是选择,我很难理解为什么这是动态 SQL。我假设您的查询(或您稍后对临时表执行的操作)比这更复杂 - 如果是这样,请不要为我们简化它。告诉我们您的整个问题会避免很多来回,因为额外的细节可能会改变答案。

【讨论】:

感谢您的评论,我用##tmpA 代替了#tmp,问题已经解决了。 @WilliamTang 不,它没有。你知道##tmpA 是做什么的吗?这将创建一个 GLOBAL 临时表。猜猜当两个人同时运行这个存储过程时会发生什么(不管你的日期范围或数据库参数是什么)。【参考方案2】:

这就是我要做的。

declare @sql varchar(max)

set @sql = 'select * from TableA where create_date >= getDate - ' + @DRange + '' and is_enabled = 1'

Select * Into #tmpA from TableA where create_date = '01/01/1000' -- to create a blank table

insert into #tmpA

exec (@sql)

select * from #tmpA

【讨论】:

以上是关于在存储过程中使用带有 exec @sql 的临时表的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver 2008 关于存储过程中的临时表。

如何执行存储过程

关于sqlserver临时表的问题,请教高手!

如何返回sqlserver 中存储过程的select的结果集

在 SQL 2008 Management Studio 中调试时查询存储过程中的临时表

SQL Server 导入和导出向导在使用临时表的存储过程中给出无效对象错误