动态 SQL 结果到 SQL 存储过程中的临时表中
Posted
技术标签:
【中文标题】动态 SQL 结果到 SQL 存储过程中的临时表中【英文标题】:Dynamic SQL results into temp table in SQL Stored procedure 【发布时间】:2010-10-14 07:20:58 【问题描述】:代码如下:
ALTER PROCEDURE dbo.pdpd_DynamicCall
@SQLString varchar(4096) = null
AS
Begin
create TABLE #T1 ( column_1 varchar(10) , column_2 varchar(100) )
insert into #T1
execute ('execute ' + @SQLString )
select * from #T1
End
问题是我想调用可以返回不同列的不同过程。 因此,我必须笼统地定义表#T1。 但我不知道怎么做。
谁能帮我解决这个问题?
【问题讨论】:
听起来你应该停止尝试使用存储过程并使用普通的旧参数化 sql 脚本。 【参考方案1】:试试:
SELECT into #T1 execute ('execute ' + @SQLString )
这闻起来真的很糟糕,就像一个 sql 注入漏洞。
更正(根据@CarpeDiem 的评论):
INSERT into #T1 execute ('execute ' + @SQLString )
另外,如果 sql 字符串不是过程,则省略 'execute'
【讨论】:
难以接受的答案,我无法完成这项工作!首先它抱怨SELECT 后没有*。当我说它时,它抱怨没有可供选择的表.. SELECT * INTO #tmp_input EXECUTE('SELECT 1 AS test') ; >>> SQL Server 数据库错误:必须指定要从中选择的表。在 SQL Server 2005 上! 我有同样的问题,如果我不知道号码怎么办。 @SQLString 返回的列数?那该怎么办。 #T1 必须在上述答案生效之前创建。 请将接受的答案更新为##T1(而不是#T1),因为这是有效的。这是由@Jesse downthread 提供的。 这是否适用于任何人而无需创建全局临时表?我收到Invalid object name '#T1'.
,你不能提前创建#T1,因为正如 OP 提到的,你不知道这些列【参考方案2】:
您可以在动态插入表时动态定义表,但问题在于临时表的范围。例如这段代码:
DECLARE @sql varchar(max)
SET @sql = 'CREATE TABLE #T1 (Col1 varchar(20))'
EXEC(@sql)
INSERT INTO #T1 (Col1) VALUES ('This will not work.')
SELECT * FROM #T1
将返回错误“无效的对象名称'#T1'。”这是因为临时表#T1 是在比执行代码块“更低的级别”创建的。为了修复,请使用全局临时表:
DECLARE @sql varchar(max)
SET @sql = 'CREATE TABLE ##T1 (Col1 varchar(20))'
EXEC(@sql)
INSERT INTO ##T1 (Col1) VALUES ('This will work.')
SELECT * FROM ##T1
希望这会有所帮助, 杰西
【讨论】:
就是这样!现在我可以在存储过程中创建表,名称通过参数传递!如果我能给 10 票! 我终于联系了 SQL 的“精神世界”并召唤了一个在那里创建的恶魔般的动态表,多亏了你! :) 实际是这样的,其他答案是错误的,谢谢【参考方案3】:注意全局临时表解决方案,因为如果两个用户同时使用相同的例程,因为所有用户都可以看到全局临时表,这可能会失败...
【讨论】:
【参考方案4】:动态创建名称中带有 GUID 的全局临时表。然后您可以通过 dyn sql 在您的代码中使用它,而不必担心另一个调用相同 sproc 的进程会使用它。当您不知道每次运行时从基础选定表中期待什么时,这很有用,因此您无法事先显式创建临时表。 ie - 你需要使用 SELECT * INTO 语法
DECLARE @TmpGlobalTable varchar(255) = 'SomeText_' + convert(varchar(36),NEWID())
-- select @TmpGlobalTable
-- build query
SET @Sql =
'SELECT * INTO [##' + @TmpGlobalTable + '] FROM SomeTable'
EXEC (@Sql)
EXEC ('SELECT * FROM [##' + @TmpGlobalTable + '] ')
EXEC ('DROP TABLE [##' + @TmpGlobalTable + ']')
PRINT 'Dropped Table ' + @TmpGlobalTable
【讨论】:
如果你有动态列名,这就是要走的路。 很好的解决方案。注意表名周围的方括号:转换为 varchar 的 NEWID 包含“-”,否则在对象名中无效。【参考方案5】:INSERT INTO #TempTable
EXEC(@SelectStatement)
【讨论】:
【参考方案6】:DECLARE @EmpGroup INT =3 ,
@IsActive BIT=1
DECLARE @tblEmpMaster AS TABLE
(EmpCode VARCHAR(20),EmpName VARCHAR(50),EmpAddress VARCHAR(500))
INSERT INTO @tblEmpMaster EXECUTE SPGetEmpList @EmpGroup,@IsActive
SELECT * FROM @tblEmpMaster
【讨论】:
【参考方案7】:CREATE PROCEDURE dbo.pdpd_DynamicCall
AS
DECLARE @SQLString_2 NVARCHAR(4000)
SET NOCOUNT ON
Begin
--- Create global temp table
CREATE TABLE ##T1 ( column_1 varchar(10) , column_2 varchar(100) )
SELECT @SQLString_2 = 'INSERT INTO ##T1( column_1, column_2) SELECT column_1 = "123", column_2 = "MUHAMMAD IMRON"'
SELECT @SQLString_2 = REPLACE(@SQLString_2, '"', '''')
EXEC SP_EXECUTESQL @SQLString_2
--- Test Display records
SELECT * FROM ##T1
--- Drop global temp table
IF OBJECT_ID('tempdb..##T1','u') IS NOT NULL
DROP TABLE ##T1
End
【讨论】:
【参考方案8】:试试下面的代码,使用 T-SQL 从存储过程输出动态创建临时表
declare @ExecutionName varchar(1000) = 'exec [spname] param1,param2 '
declare @sqlStr varchar(max) = ''
declare @tempTableDef nvarchar(max) =
(
SELECT distinct
STUFF(
(
SELECT ','+a.[name]+' '+[system_type_name]
+'
' AS [text()]
FROM sys.dm_exec_describe_first_result_set (@ExecutionName, null, 0) a
ORDER BY a.column_ordinal
FOR XML PATH ('')
), 1, 1, '') tempTableDef
FROM sys.dm_exec_describe_first_result_set (@ExecutionName, null, 0) b
)
IF ISNULL(@tempTableDef ,'') = '' RAISERROR( 'Invalid SP Configuration. At least one column is required in Select list of SP output.',16,1) ;
set @tempTableDef='CREATE TABLE #ResultDef
(
' + REPLACE(@tempTableDef,'
','') +'
)
INSERT INTO #ResultDef
' + @ExecutionName
Select @sqlStr = @tempTableDef +' Select * from #ResultDef '
exec(@sqlStr)
【讨论】:
【参考方案9】:不确定我是否理解得很好,但也许您可以在字符串中形成 CREATE 语句,然后执行该字符串?这样您就可以根据需要添加任意数量的列。
【讨论】:
但是,我不知道列,它是动态的。以上是关于动态 SQL 结果到 SQL 存储过程中的临时表中的主要内容,如果未能解决你的问题,请参考以下文章
为啥这个 SQL 存储过程需要创建一个临时表才能工作(返回结果)?
如何将单个结果集从返回多个集的 SQL 存储过程保存到临时表?