0

是否可以检测当前存储过程是否被INSERT-EXEC语句调用?

是的,我知道我们可能不想再使用INSERT-EXEC语句……这不是我要问的问题。

我使用的原因INSERT-EXEC是因为我希望促进存储过程的重用,而不是一直重写相同的 SQL。

这就是我关心的原因:
在这种情况下,一旦请求INSERT-EXECa ,原始错误消息就会丢失。ROLLBACK因此,创建的任何记录现在都将是孤立的。

例子:

ALTER PROCEDURE [dbo].[spa_DoSomething]
(
    @SomeKey    INT,
    @CreatedBy  NVARCHAR(50)
)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        BEGIN TRANSACTION

        -- SQL runs and throws an error of some kind.

        COMMIT TRAN
    END TRY
    BEGIN CATCH

        IF @@TRANCOUNT > 0
            ROLLBACK TRAN

        -- If this procedure is called using an INSERT-EXEC
        -- then the original error will be lost at this point because
        -- "Cannot use the ROLLBACK statement within an INSERT-EXEC statement." 
        -- will come-up instead of the original error.

        SET @ErrorMessage = ERROR_MESSAGE();
        SET @ErrorSeverity =    ERROR_SEVERITY();
        SET @ErrorState =       ERROR_STATE();

        RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
    END CATCH

    RETURN @@Error
END
4

2 回答 2

1

INSERT--EXECUTE基于您不能嵌套... 语句的事实,我想出了一些杂物(好吧,这是一个大杂物) 。基本上,如果您的“问题”过程是 an 的目标INSERT--EXECUTE,并且它本身包含一个INSERT--EXECUTE,那么将引发错误。要完成这项工作,您必须在INSERT--EXECUTE过程中进行(可能毫无意义的)调用,并将其包装在TRY--CATCH具有适当处理的块中。尴尬和迟钝,但如果没有其他问题,它可能值得一试。

使用以下内容进行测试。这将创建三个过程:

IF objectproperty(object_id('dbo.Foo1'), 'isProcedure') = 1
    DROP PROCEDURE dbo.Foo1
IF objectproperty(object_id('dbo.Foo2'), 'isProcedure') = 1
    DROP PROCEDURE dbo.Foo2
IF objectproperty(object_id('dbo.Foo3'), 'isProcedure') = 1
    DROP PROCEDURE dbo.Foo3

GO
--  Returns a simple data set
CREATE PROCEDURE Foo1

AS

    SET NOCOUNT on

    SELECT name
     from sys.databases

GO
--  Calls Foo1, loads data into a local temp table, then returns those contents
CREATE PROCEDURE Foo2

AS

    SET NOCOUNT on

    CREATE TABLE #Temp (DBName sysname not null)

    BEGIN TRY
        INSERT #Temp (DBName)
         EXECUTE Foo1
    END TRY

    BEGIN CATCH
        IF ERROR_NUMBER() = 8164
            PRINT 'Nested INSERT EXECUTE'
        ELSE
            PRINT 'Unanticipated err: ' + cast(ERROR_NUMBER() as varchar(10))
    END CATCH


    SELECT *
     from #Temp

GO
--  Calls Foo2, loads data into a local temp table, then returns those contents
CREATE PROCEDURE Foo3

AS

    SET NOCOUNT on

    CREATE TABLE #Temp2 (DBName sysname not null)

    INSERT #Temp2 (DBName)
     EXECUTE Foo2

    SELECT *
     from #Temp2
GO

EXECUTE Foo1将返回“基础”数据集。

EXECUTE Foo2将调用 Foo1,将数据加载到临时表中,然后返回该表的内容。

EXECUTE Foo3尝试做与 Foo2 相同的事情,但它调用 Foo2。这会导致嵌套INSERT--EXECUTE错误,由 Foo2 检测和处理TRY--CATCH

于 2011-07-07T14:34:12.180 回答
0

也许@@NESTLEVEL 可以提供帮助:

http://msdn.microsoft.com/en-us/library/ms187371.aspx

于 2011-07-07T14:26:12.930 回答