【问题标题】:Avoiding "An INSERT EXEC statement cannot be nested"避免“不能嵌套 INSERT EXEC 语句”
【发布时间】:2016-05-02 19:48:49
【问题描述】:

我知道这不可能嵌套 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 调用我的过程,我想跳过它

【问题讨论】:

  • 你的问题很清楚。但你想做什么还不清楚。所以可能你不会得到最佳解决方案。你的脚本是什么样的?

标签: sql sql-server insert-into


【解决方案1】:

如上所述here

这是尝试从 存储过程链。 SQL Server 中的一个限制是您可以 一次只有一个 INSERT-EXEC 处于活动状态。我建议看 How to Share Data Between Stored Procedures 这是一个非常 有关解决此类问题的模式的详尽文章。

试试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')

【讨论】:

    【解决方案2】:

    一种天真的方法是使用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

    【讨论】:

    • 我确信我已经尝试过了,但当时并没有奏效。但看起来它确实运作良好。我现在没有在我的生产代码中使用它,但无论如何有一个答案是件好事。
    【解决方案3】:

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

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

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

    --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
    

    【讨论】:

    • 这仅在您控制外部和内部插入并且知道它们使用相同的表名时才有效 - 此时内部过程可以传递一个参数来告诉它是否可以使用INSERT...EXEC ,而不是试图检测情况。
    猜你喜欢
    • 2014-07-07
    • 2013-05-17
    • 2017-10-18
    • 2019-11-12
    • 2020-01-21
    • 2018-03-20
    • 2012-04-24
    • 1970-01-01
    相关资源
    最近更新 更多