【问题标题】:Rolling back 2 stored procedures if the second stored procedure did not insert any rows如果第二个存储过程没有插入任何行,则回滚 2 个存储过程
【发布时间】:2020-10-13 11:31:05
【问题描述】:

以下存储过程INSERT1 可以正常工作。它根据 data_type_id 触发存储过程INSERT2 并将数据插入到单独的表中。但是我想编辑这个存储过程INSERT1(或INSERT2),这样,如果没有行通过INSERT2 插入TABLE2,那么我想回滚INSERT1。我在想也许可以使用类似的东西

Set @rows_affected = @@rowcount
         
if ((@rows_affected = 0))
     ROLLBACK TRANSACTION

但我不确定如何编辑该过程,如果没有通过存储过程 INSERT2 插入任何行,则回滚两个存储过程 INSERT1INSERT2

Create PROCEDURE INSERT1 (
    @JsonData NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @err int
    declare @submission_id varchar(32)
    declare @dataset_id varchar(32)
    declare @json varchar(max) 
    DECLARE @v_data_type_id varchar(50)

    Set @v_data_type_id = (SELECT  data_type_id
    FROM OPENJSON (@JsonData, N'$')
    WITH (data_type_id varchar(32) '$.dataTypeId'))

    set @json = @JsonData

    Begin TRANSACTION

    INSERT INTO TABLE1 (
        submission_id,
        data_set_id,
        data_type_id, 
    )
    SELECT *
    FROM OPENJSON (@json, N'$') WITH (
        submission_id varchar(32) N'$.submissionId',
        data_set_id varchar(32) N'$.dataSetId',
        data_type_id varchar(50) N'$.dataTypeId',
    ) 

    if ((@v_data_type_id = '1'))
    BEGIN 
        exec [dbo].[INSERT2] @json  
  
IF @@ROWCOUNT = 0
            BEGIN
                ROLLBACK TRANSACTION
                RETURN
            END
        END
    COMMIT TRANSACTION
END
GO

这是 INSERT2 脚本:

CREATE PROCEDURE INSERT2 (
    @Json_PMU1 NVARCHAR(MAX)
)
AS
  BEGIN
    DECLARE @err int
    DECLARE @submission_id varchar(32)
    DECLARE @dataset_id varchar(32)

SELECT  @submission_id = submission_id,
        @dataset_id = data_set_id
from openjson(@Json_PMU1, N'$')
with (
submission_id varchar(32) N'$.submissionId',
data_set_id varchar(32) N'$.dataSetId'
)

INSERT INTO TABLE2 (
        name,
        contact_number,
        submission_id,
        data_set_id
)
select  Name as name,
        contactNumber as contact_number,
        @submission_id as submission_id, 
        @dataset_id as data_set_id
        
--into TABLE2

from openjson (@Json_PMU1, '$.data.Table2')
with (
    Name varchar(255) ,
    contactNumber char(11) 
)
SELECT @err = @@ERROR
    RETURN (@err)
    
    
    
END
    

【问题讨论】:

  • 你不确定这里有什么?
  • @Larnu 如何编辑存储过程,如果 INSERT2 插入 0 行则回滚整个过程,INSERT1 & INSERT2
  • 在插入之前插入begin tran,之后有条件的回滚?

标签: json sql-server database stored-procedures triggers


【解决方案1】:

你在正确的轨道上。你需要在第一个INSERT之前打开一个事务,然后在第二个存储过程执行之后检查rowcount。只需确保[dbo].[INSERT2] 中的最后一个操作是INSERT,这样它就不会影响您的@@ROWCOUNT 值。

Create PROCEDURE INSERT1 (
        @JsonData NVARCHAR(MAX)
    )
AS
BEGIN
    DECLARE @err int
    declare @submission_id varchar(32)
    declare @dataset_id varchar(32)
    declare @json varchar(max) 
    DECLARE @v_data_type_id varchar(50)


    Set @v_data_type_id = (SELECT  data_type_id
        FROM OPENJSON (@JsonData, N'$')
      WITH (
        data_type_id varchar(32) '$.dataTypeId'))

    set @json = @JsonData

    BEGIN TRAN

        INSERT INTO TABLE1 (
        submission_id,
        data_set_id,
        data_type_id
        )
            SELECT *
            FROM OPENJSON (@json, N'$') WITH (
            submission_id varchar(32) N'$.submissionId',
            data_set_id varchar(32) N'$.dataSetId',
            data_type_id varchar(50) N'$.dataTypeId'
        ) 

        IF(( @v_data_type_id = '1'))
        BEGIN 

            exec [dbo].[INSERT2] @json  

            IF @@ROWCOUNT = 0
            BEGIN
                ROLLBACK TRAN
                RETURN
            END
        END
    COMMIT TRAN
END
GO

在您的INSERT2 过程中,您要做的最后一件事是选择错误,因此您最终会影响影响@@ROWCOUNT 值,迫使它始终返回 1。插入语句必须是您的最后一个操作INSERT2 存储过程,以便将正确的值返回给调用过程。

CREATE PROCEDURE INSERT2 (
    @Json_PMU1 NVARCHAR(MAX)
)
AS
  BEGIN
    DECLARE @err int
    DECLARE @submission_id varchar(32)
    DECLARE @dataset_id varchar(32)

SELECT  @submission_id = submission_id,
        @dataset_id = data_set_id
from openjson(@Json_PMU1, N'$')
with (
submission_id varchar(32) N'$.submissionId',
data_set_id varchar(32) N'$.dataSetId'
)

INSERT INTO TABLE2 (
        name,
        contact_number,
        submission_id,
        data_set_id
)
select  Name as name,
        contactNumber as contact_number,
        @submission_id as submission_id, 
        @dataset_id as data_set_id
        
--into TABLE2

from openjson (@Json_PMU1, '$.data.Table2')
with (
    Name varchar(255) ,
    contactNumber char(11) 
)

END

【讨论】:

  • 我刚刚编辑了我的存储过程,并使用适用于 INSERT1 而不适用于 INSERT2 的数据运行了这些过程,但不幸的是它仍然在 INSERT1 中提交了数据:(受影响的 1 行)(受影响的 0 行) OK 程序更新得很好,但似乎仍然无法正常工作:(
  • 这个答案和大卫布朗的答案都应该完全符合您的要求。查看更新后的代码会很有帮助。
  • 我已经更新了问题中的脚本。我感谢你的耐心。我对此很陌生。 :)
  • INSERT1 存储过程中的一切似乎都正常。可以分享一下 INSERT2 存储过程代码吗?
  • 更新了我的答案。我会指出,这只是解决这个问题的一种方法,而且它是相当简单的。大卫布朗的回答也是一个不错的选择。他继续向您展示了如何通过正确的错误处理来做到这一点。最终,无论您选择什么,我认为您的主要问题在于您的 INSERT2 实现。
【解决方案2】:

您不应该只是回滚。您应该在 INSERT2 中抛出异常,然后回滚,然后将异常发送给客户端,以通知客户端请求的进程没有发生。 EG

CREATE OR ALTER PROCEDURE INSERT1 ( @JsonData NVARCHAR(MAX) )
AS
  BEGIN
  SET XACT_ABORT ON
  BEGIN TRANSACTION
  BEGIN TRY
    DECLARE @err int
    declare @submission_id varchar(32)
    declare @dataset_id varchar(32)
    declare @json varchar(max) 
    DECLARE @v_data_type_id varchar(50)


    Set @v_data_type_id = (
        SELECT  data_type_id 
        FROM OPENJSON (@JsonData, N'$') WITH (  data_type_id varchar(32) '$.dataTypeId') )

    set @json = @JsonData

    INSERT INTO TABLE1 (submission_id, data_set_id, data_type_id )
    SELECT *
    FROM OPENJSON (@json, N'$') WITH (
        submission_id varchar(32) N'$.submissionId',
        data_set_id varchar(32) N'$.dataSetId',
        data_type_id varchar(50) N'$.dataTypeId'
      ) 

   if( @v_data_type_id = '1' )
   BEGIN 
     exec [dbo].[INSERT2] @json  
   End

   COMMIT TRANSACTION;
END TRY
BEGIN CATCH
  IF @@TRANCOUNT > 0 ROLLBACK
  THROW;
END CATCH
END
go

【讨论】:

  • +1 用于将 SET XACT_ABORT ON; 添加到带有显式事务的 proc 中。这是一个经常被忽视的细节,如果省略,可能会导致客户端超时后出现问题。
  • @David 我刚刚编辑了我的存储过程,并使用适用于 INSERT1 和 not 的数据运行了这些过程,但不幸的是它仍然在 INSERT1 中提交了数据: (1 行受影响)(0 行受影响)OK
  • @codingnoob 是的,有 1 行受到影响。然后回滚。这些消息毫无意义。
  • @GSerg 我想要的是,如果在第二个存储过程中插入了 0 行,那么我想回滚第一个存储过程。我刚刚在TABLE1里面看了,确实已经插入了记录。
  • 如果插入零行,您必须在 INSERT2 中抛出或 RAISERROR。
猜你喜欢
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
相关资源
最近更新 更多