如何访问通过调用TSQL中的存储过程生成的当前作用域中的数据集?

问题背景

生成和访问固定列布局的数据很容易。 您可以预先创建本地临时表,并通过调用存储过程来填充它们。

另一方面,如果要使用动态列布局生成数据,则通常必须动态构建SQL语句并使用“exec sp_executesql”执行它。 由于数据布局在运行时是未知的,因此无法预先创建临时表,并且一旦在“exec sp_executesql”语句内部创建,那里创建的任何临时表都将绑定到该范围,并在调用返回时消失,所以访问数据要困难得多(即你的选择更加有限)。

我的具体情况

我有一个查询需要访问动态生成的表中的数据。

该表由存储过程生成,该存储过程动态构建查询,将其存储在变量“@sql nvarchar(max)”中,并通过调用“exec sp_executesql @statement = @sql”来运行它。

@sql语句类似于“select * into #temptable from ...”,但#temptable在“exec sp_executesql”返回时被销毁。 对此的一个快速解决方法是使用“## temptable”而不是(即全局临时表),因为它在存储过程返回时仍然存活并且我可以在调用范围内轻松访问它(因为它具有已知/静态名称)。

我不喜欢这个解决方案,因为全局临时表不是线程安全的(名称collistion-wise),而且我也不想混淆动态生成的唯一名称,因为我最终不得不使用更多的动态SQL来访问它们......这让我马上回到原点,使数据在SP之外无法访问。

我不认为返回表变量(通过输出参数)是一个选项(SQL Server 2008也是新的),除非可以在不必定义静态表类型的情况下完成。 我的存储过程生成的表是动态的,并且取决于传递的输入参数。

内联表值函数不是一个选项,因为我正在运行代码循环来构建@sql查询并调用“exec sp_executesql”。

多语句表值函数(而不是存储过程)也不是一个选项,因为这样的函数必须有一个定义明确的表格格式,而我正在运行dyanmic SQL来返回一个具有可变数目列和列名称取决于输入参数值。

我真正想要做的就是将动态查询的结果集选择到一个新表中,但是我发现它很困难,因为以上都不适用; 特别令人恼火的是本地临时表如何不是本地会话,而是本地存储过程,以便它们在返回时消失。 我见过的唯一解决方案坚持使用OPENROWSET是唯一的方法,但我不想在存储过程中弄乱连接字符串,出于同样的原因,我不想包含唯一名称管理代码。 ..这只是比它应该更复杂的方式。

总之,我只是想执行动态SQL来生成未知格式的数据集,并且能够从调用范围轻松访问它。


sp_executesql之前创建临时表:它仍然处于“内部”范围的范围内,如sp_executesql

更改SQL以执行INSERT而不是SELECT..INTO...

编辑:

使桌子足够宽以覆盖所有选项。

坦率地说,SQL被设计为与固定表定义一起工作:可变输出签名(表)导致您遇到的问题...


一种笨重但可能的选择是在调用者中创建单列表格,然后在被调用者中对其进行修改。 这解决了范围问题,但让事情变得更加困难......

如果构建一个接受输入和输出表名的存储过程,这可以使第二个表看起来与第一个表完全一样,那么可以使用更通用的解决方案。

tempdb.INFORMATION_SCHEMA.COLUMNS选择可让您找到有关任何临时表的列信息(可通过表名是否以#开头来检测)。 这是一个例子:

CREATE TABLE #blah (a int)
SELECT *
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE Object_id('tempdb.dbo.' + TABLE_NAME) = Object_id('tempdb.dbo.#blah')
DROP TABLE #blah

请注意,视图中的表名不是#blah (它可能类似于#blah___{lots of underscores}___00000000021D因此使用Object_id()来关联这两者。

要实际使用它,而不是用数据填充第一个表格,然后修改第二个表格并将数据复制到它中,我建议首先创建一个空表格,方法是运行一个添加TOP 0WHERE 1 = 0 ,然后用表格复制SP将表格结构复制到正确的表格中,然后运行数据过程以实现仅插入一次到正确的表格。

就像我说的那样,笨重,但在一些没有其他选择的狭窄情况下可能会有用。


所以,我从存储过程的插入结果复制我的答案到临时表中。 希望能帮助到你。 是的,它又是全局临时表,唯一不同的是在那里附加了GUID。


我遇到了同样的问题,保罗的建议就是这样做的。 这里的主要部分是使用NEWID()来避免多个用户同时运行存储过程/脚本,这是全局临时表的痛处。

DECLARE @sql varchar(max) = '', 
@tmp_global_table varchar(255) = '##global_tmp_' + CONVERT(varchar(36), NEWID())
SET @sql = @sql + 'select * into [' + @tmp_global_table + '] from YOURTABLE'
EXEC(@sql)

EXEC('SELECT * FROM [' + @tmp_global_table + ']')
链接地址: http://www.djcxy.com/p/24737.html

上一篇: How to access dataset in current scope generated by a call to a stored procedure in TSQL?

下一篇: SQL query to remove duplicates from large tables using join