我正在尝试放置一个存储过程,然后在交易中重新创建它,然后重新创建它。
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
当我运行上面的脚本时,我会收到以下错误:
Msg 156, Level 15, State 1, Line 9
Incorrect syntax near the keyword 'PROCEDURE'.
Msg 137, Level 15, State 2, Line 31
Must declare the scalar variable "@date".
我在集合上有弯曲的线,@date。
if语句和创建语句本身都可以正常工作。
您可以使用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;
这种方法的另一个好处(或一个缺点,取决于您的部署过程),这使得在存储过程中的任何现有权限完好无损,这与掉落和创建不同。
只是为了证明此可以在交易中完成,这是一个演示脚本:
create procedure dbo.A
as
select 1 as T
go
exec dbo.A
go
begin transaction
go
IF OBJECT_ID(N'dbo.A', N'P') IS NOT NULL
BEGIN
EXEC('drop procedure dbo.A')
END
go
create procedure dbo.A
as
select penguin from sys.objects --This will fail
go
IF OBJECT_ID(N'dbo.A', N'P') IS NOT NULL
BEGIN
commit
END
ELSE
BEGIN
rollback transaction
END
go
exec dbo.A
尝试创建新的A
过程时会产生错误,并且回滚恢复回到A
的原始版本。这只能真正起作用(如在此处),其中创建新版本的A
会导致硬错误,以便我们以后可以检测到并决定rollback
而不是commit
。
话虽如此,我仍然自己使用耶洛恩的回答。
过程定义必须在其自己的批处理中。在管理工作室中,您将使用
的两行go
在create procedure
之前和end
之后。不幸的是交易不能跨越多批次。
您可以在exec
调用中创建过程?喜欢:
exec ('create procedure dbo.MyProc as ...');
使用此代码,这是我的工作示例。
根据您的表和要求对其进行修改。
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
我不知道您想在那里做什么,但是我可以看到此代码有一些明显的事情,它应该看起来像这样...
注意到您创建过程必须是批处理中唯一的语句,这意味着您不能在一次交易中包装掉落并创建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