避免 "An INSERT EXEC statement cannot be nested"

Avoiding "An INSERT EXEC statement cannot be nested"

我知道这不可能嵌套 insert ... exec 语句,但我仍然很感兴趣 - 有没有办法检查我是否已经有活动的 insert ... exec 以避免实际错误?

所以我想要这样的东西:

....
if <check if I have outer insert into exec> = 0
    insert into <#some temporary table>
    exec <stored procedure>

换句话说 - insert ... exec 是可选的,拥有它很好,但如果有人试图用外部 insert ... exec

调用我的过程,我想跳过它

如所述here

This is a common issue when attempting to 'bubble' up data from a chain of stored procedures. A restriction in SQL Server is you can only have one INSERT-EXEC active at a time. I recommend looking at How to Share Data Between Stored Procedures which is a very thorough article on patterns to work around this type of problem.

试试 OpenRowset

INSERT INTO #YOUR_TEMP_TABLE
SELECT * FROM OPENROWSET ('SQLOLEDB','Server=(local);TRUSTED_CONNECTION=YES;','set fmtonly off EXEC [ServerName].dbo.[StoredProcedureName] 1,2,3')

一种天真的方法是使用 TRY/CATCH 块:

BEGIN
DECLARE @isNested BIT = 0;

  BEGIN TRY
      BEGIN TRANSACTION;
      EXEC p2;
      ROLLBACK;  --COMMIT;
  END TRY
  BEGIN CATCH
    -- Msg 8164 An INSERT EXEC statement cannot be nested.
    IF ERROR_NUMBER() = 8164 SET @isNested = 1;
    ROLLBACK;
  END CATCH

SELECT @isNested;
END

db<>fiddle demo

我正在使用 OBJECT_ID 检查内部过程中是否存在临时 table 以确保我们没有嵌套插入执行场景。

当我们检查 table 不存在时,我们创建 table 并插入到 table 中。

我在下面提供了示例代码供您参考。

--Procedure for INSERT...EXEC
CREATE PROCEDURE ValuesGetForInsert
AS
BEGIN
    SELECT 1
    UNION ALL
    SELECT 2
    UNION ALL
    SELECT 3;
END
GO

--Outer Insert Procedure
CREATE PROCEDURE dbo.OuterInsert
AS
BEGIN
IF OBJECT_ID('tempdb..#Table1') IS NULL
BEGIN
    CREATE TABLE #Table1(a int);
    INSERT INTO #Table1(a)
    EXECUTE ValuesGetForInsert;
END
    EXECUTE InnerInsert;

    SELECT 'OuterInsert',* FROM #Table1;
END
GO

--Inner Insert Procedure
CREATE PROCEDURE dbo.InnerInsert
AS
BEGIN
    IF OBJECT_ID('tempdb..#Table1') IS NULL
    BEGIN
        CREATE TABLE #Table1(a int);
        INSERT INTO #Table1(a)
        EXECUTE ValuesGetForInsert;
    END
    SELECT 'Inner Insert', * FROM #Table1
END
GO

--Executing outer insert or inner insert indepenently
EXECUTE dbo.OuterInsert;
EXECUTE dbo.InnerInsert;
GO