SQL Server:无法在事务中DROP和CREATE SP

时间:2017-10-04 09:34:45

标签: sql-server stored-procedures transactions

我正在尝试删除存储过程(如果存在),然后在事务内部重新创建它。

npm run start

当我运行上面的脚本时,我收到以下错误:

BEGIN TRANSACTION
BEGIN TRY

IF OBJECT_ID(N'dbo.GET_DATA', N'P') IS NOT NULL
BEGIN 
    DROP PROCEDURE [dbo].[GET_DATA]
END

CREATE PROCEDURE [dbo].[GET_DATA]
    @date datetime2
AS
    SET NOCOUNT ON
BEGIN

    SELECT 
        dbo.Products.product_cod AS 'product_cod',
        dbo.Product_Types.name AS 'product_type_name',
        dbo.UM.name AS 'um_name',
        dbo.Products.category_id AS 'category_id',
        dbo.Bins_Products.bin_id AS 'product_bin_id' 

    FROM dbo.Products
        LEFT JOIN dbo.Product_Types on Products.product_type_id = Product_Types.product_type_id
        LEFT JOIN dbo.UM on Products.um_id = UM.um_id
        LEFT JOIN Bins_Products ON Bins_Products.product_id = Products.product_id
    WHERE
        Products.update_date >= @date
END
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE() AS 'ErrorMessage'
    ROLLBACK TRANSACTION
END CATCH

我在SET和@date上有一些波浪线。

IF语句和create语句本身都可以正常工作。

5 个答案:

答案 0 :(得分:2)

您可以使用EXEC在事务中创建过程,但这非常不方便,因为需要对整个身体进行转义。更好的方法是确保存储过程始终存在,然后执行ALTER,这不需要单独的事务:

IF OBJECT_ID('Foo', 'P') IS NULL
    EXEC ('CREATE PROCEDURE Foo AS BEGIN RETURN END;');
GO
ALTER PROCEDURE Foo(@Arg INT) AS BEGIN
    ...
END;

这种方法的另一个好处(或缺点,取决于您的部署过程)是,这会保留存储过程的任何现有权限,而不像删除和创建它。

答案 1 :(得分:2)

只是为了证明这个可以在一个事务中完成,这是一个演示脚本:

A

尝试创建新的A过程时会产生错误,并且回滚会恢复为A的原始版本。这只能真正起作用(如此处),创建新版rollback会导致硬错误,以便我们可以在之后检测到并决定commit而不是test

话虽这么说,我仍然会自己使用Jeroen's answer

答案 2 :(得分:0)

过程定义必须在其自己的批次中。在Management Studio中,您需要添加两行

go

create procedure之前和end之后。不幸的是,交易不能跨越多个批次。

你可以在exec电话中创建程序吗?像:

exec ('create procedure dbo.MyProc as ...');

答案 3 :(得分:0)

使用此代码,这是我的工作示例。

根据您的表格和要求进行修改。

USE [DatabaseName]
GO

/****** Object:  StoredProcedure [dbo].[_AdvancePaymentDelete]    Script Date: 10/04/2017 15:12:43 ******/
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[_AdvancePaymentDelete]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[_AdvancePaymentDelete]
GO

USE [DatabaseName]
GO

/****** Object:  StoredProcedure [dbo].[_AdvancePaymentDelete]    Script Date: 10/04/2017 15:12:43 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[_AdvancePaymentDelete] 
(
        @_ADVANCEPAYMENTID_PK uniqueidentifier,
        @_COMPANYID_PK uniqueidentifier ,
        @_COMPANYDETID_PK uniqueidentifier ,
        @_USERID_PK uniqueidentifier
          )
AS
BEGIN
        BEGIN TRANSACTION;
        SAVE TRANSACTION MySavePoint;
    DECLARE @ErrorMessage nvarchar(MAX) = 'OK';

        BEGIN TRY
UPDATE [dbo].[_ADVANCEPAYMENT] SET _ISDELETED = N'2'

 WHERE _COMPANYID_PK = @_COMPANYID_PK AND _COMPANYDETID_PK = @_COMPANYDETID_PK AND _USERID_PK = @_USERID_PK AND _ADVANCEPAYMENTID_PK = @_ADVANCEPAYMENTID_PK AND _ISDELETED = N'1'

UPDATE [dbo].[_ADVANCEPAYMENTDET]  SET _ISDELETED = N'2'

 WHERE _COMPANYID_PK = @_COMPANYID_PK AND _COMPANYDETID_PK = @_COMPANYDETID_PK AND _USERID_PK = @_USERID_PK AND _ADVANCEPAYMENTID_PK = @_ADVANCEPAYMENTID_PK AND _ISDELETED = N'1'


    END TRY
    BEGIN CATCH
   IF @@TRANCOUNT > 0
        BEGIN

    ROLLBACK TRANSACTION MySavePoint; -- rollback to MySavePoint
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    SET @ErrorMessage = 'Error No : '  + CAST ( ERROR_NUMBER() AS nvarchar(MAX)) + CHAR(13) + 'Line No : '  + CAST ( ERROR_LINE() AS nvarchar(MAX))+ CHAR(13) + 'Procedure Name : '  + QUOTENAME(OBJECT_SCHEMA_NAME(@@PROCID)) + '.' + QUOTENAME(OBJECT_NAME(@@PROCID)) + CHAR(13) + 'Error Message : '  + ERROR_MESSAGE();
    RAISERROR( @ErrorMessage, @ErrorSeverity, @ErrorState);
        END
    END CATCH

    COMMIT TRANSACTION 
END; 

SELECT @ErrorMessage 

GO

答案 4 :(得分:0)

我不知道你在那里尝试做什么,但是我可以看到这个代码有一些明显的问题,看起来应该是这样......

请注意,创建过程必须是批处理中的唯一语句,这意味着您无法在一个事务中包装drop和create proc。

IF OBJECT_ID(N'dbo.GET_DATA', N'P') IS NOT NULL
BEGIN 
    DROP PROCEDURE [dbo].[GET_DATA]
END
GO

CREATE PROCEDURE [dbo].[GET_DATA]
    @date datetime2
AS
BEGIN                       --<-- Proc body start
    SET NOCOUNT ON;

BEGIN TRY
    BEGIN TRANSACTION;

            SELECT 
                dbo.Products.product_cod AS 'product_cod',
                dbo.Product_Types.name AS 'product_type_name',
                dbo.UM.name AS 'um_name',
                dbo.Products.category_id AS 'category_id',
                dbo.Bins_Products.bin_id AS 'product_bin_id' 

            FROM dbo.Products
                LEFT JOIN dbo.Product_Types on Products.product_type_id = Product_Types.product_type_id
                LEFT JOIN dbo.UM on Products.um_id = UM.um_id
                LEFT JOIN Bins_Products ON Bins_Products.product_id = Products.product_id
            WHERE
                Products.update_date >= @date;
    COMMIT TRANSACTION;
END TRY

BEGIN CATCH
      IF (@@TRANCOUNT > 0)   -- Check for open transactions before you try to rollback
      BEGIN
          ROLLBACK TRANSACTION;
      END

    SELECT ERROR_MESSAGE() AS 'ErrorMessage'

END CATCH

END                     --<-- Proc body End 
GO