HAJ*_*JAJ 88 sql-server code-reuse sql-server-2008
我有三个存储过程Sp1
,Sp2
和Sp3
.
第一个(Sp1
)将执行第二个(Sp2
)并保存返回的数据@tempTB1
,第二个将执行第三个(Sp3
)并将数据保存到@tempTB2
.
如果我执行Sp2
它将工作,它将返回我的所有数据Sp3
,但问题在于Sp1
,当我执行它时,它将显示此错误:
INSERT EXEC语句不能嵌套
我试图改变它的位置,execute Sp2
它显示另一个错误:
无法在INSERT-EXEC语句中使用ROLLBACK语句.
edd*_*ves 90
当尝试从存储过程链中"冒泡"数据时,这是一个常见问题.SQL Server中的限制是一次只能激活一个INSERT-EXEC.我建议查看如何在存储过程之间共享数据,这是一个关于解决此类问题的模式的非常全面的文章.
例如,解决方法可能是将Sp3转换为表值函数.
小智 17
这是在SQL Server中执行此操作的唯一"简单"方法,没有一些巨大的复杂创建函数或执行的sql字符串调用,这两者都是可怕的解决方案:
例:
INSERT INTO #YOUR_TEMP_TABLE
SELECT * FROM OPENROWSET ('SQLOLEDB','Server=(local);TRUSTED_CONNECTION=YES;','set fmtonly off EXEC [ServerName].dbo.[StoredProcedureName] 1,2,3')
Run Code Online (Sandbox Code Playgroud)
注意:您必须使用'set fmtonly off',并且您不能在openrowset调用内部为此添加动态sql,对于包含存储过程参数的字符串或表名称.这就是为什么你必须使用临时表而不是表变量,这本来是更好的,因为它在大多数情况下执行临时表.
小智 10
好的,jimhark鼓励这里是旧的单一哈希表方法的一个例子: -
CREATE PROCEDURE SP3 as
BEGIN
SELECT 1, 'Data1'
UNION ALL
SELECT 2, 'Data2'
END
go
CREATE PROCEDURE SP2 as
BEGIN
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
INSERT INTO #tmp1
EXEC SP3
else
EXEC SP3
END
go
CREATE PROCEDURE SP1 as
BEGIN
EXEC SP2
END
GO
/*
--I want some data back from SP3
-- Just run the SP1
EXEC SP1
*/
/*
--I want some data back from SP3 into a table to do something useful
--Try run this - get an error - can't nest Execs
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
DROP TABLE #tmp1
CREATE TABLE #tmp1 (ID INT, Data VARCHAR(20))
INSERT INTO #tmp1
EXEC SP1
*/
/*
--I want some data back from SP3 into a table to do something useful
--However, if we run this single hash temp table it is in scope anyway so
--no need for the exec insert
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
DROP TABLE #tmp1
CREATE TABLE #tmp1 (ID INT, Data VARCHAR(20))
EXEC SP1
SELECT * FROM #tmp1
*/
Run Code Online (Sandbox Code Playgroud)
小智 9
我解决这个问题的方法一直是使用单个散列临时表在任何被调用的procs范围内的原则.所以,我在proc参数中有一个选项开关(默认设置为off).如果打开它,则被调用的proc会将结果插入到调用proc中创建的临时表中.我认为在过去我已经更进一步,并在被调用的proc中放入一些代码来检查作用域中是否存在单个哈希表,如果是,则插入代码,否则返回结果集.似乎运行良好 - 在proc之间传递大数据集的最佳方式.
这个技巧对我有用。
你在远程服务器上没有这个问题,因为在远程服务器上,最后一个插入命令等待上一个命令的结果执行。在同一台服务器上不是这样。
利用这种情况作为解决方法。
如果您有创建链接服务器的正确权限,请执行此操作。创建与链接服务器相同的服务器。
现在您在 SP1 中的 Sql 命令是
insert into @myTempTable
exec THISSERVER.MY_DATABASE_NAME.MY_SCHEMA.SP2
Run Code Online (Sandbox Code Playgroud)
相信我,即使您在 SP2 中有动态插入,它也能工作
我发现一种解决方法是将其中一个 prods 转换为表值函数。我意识到这并不总是可能的,并引入了它自己的局限性。但是,我总是能够找到至少一个程序是一个很好的候选者。我喜欢这个解决方案,因为它没有对解决方案引入任何“黑客”。
我在尝试将 Stored Proc 的结果导入临时表时遇到了这个问题,并且 Stored Proc 作为其自身操作的一部分插入到临时表中。问题是 SQL Server 不允许同一进程同时写入两个不同的临时表。
接受的 OPENROWSET 答案工作正常,但我需要避免在我的过程中使用任何动态 SQL 或外部 OLE 提供程序,所以我走了一条不同的路线。
我发现的一种简单解决方法是将存储过程中的临时表更改为表变量。它的工作方式与临时表完全相同,但不再与我的其他临时表插入冲突。
只是为了阻止评论,我知道你们中的一些人即将写,警告我不要将表变量作为性能杀手......我能告诉你的是,在 2020 年,不要害怕表变量会带来好处。如果这是 2008 年,并且我的数据库托管在具有 16GB RAM 并运行 5400RPM 硬盘的服务器上,我可能会同意您的看法。但现在是 2020 年,我有一个 SSD 阵列作为我的主要存储设备和数百个内存。我可以将我整个公司的数据库加载到一个表变量中,并且仍然有足够的 RAM 可用。
表变量重新出现在菜单上!