0

我想删除一个包含标题、子标题和行项目详细信息的订单,然后再用替换子标题、行项目详细信息现在可能是什么来写出相同的订单。当我尝试用更改写回较新版本时,出现 pk 违规错误。经过分析,我发现即使我的 DELETE 语句似乎有效,但在发出它们(例如 x 行受影响)之后——目标表保持不变。因此,这将解释 pk vio 问题。我错过了什么?

这是其中的一种说法:

       -- detail level (drop products)
       DELETE dprods FROM [SQLsever].[WIP].[order].DropProducts as dprods
        INNER JOIN #dropprods t on t.OrderId = dprods.OrderId
          AND t.OrderDropId = dprods.OrderDropId
          AND t.DropProdId = dprods.DropProdId;

发出语句后,我仍然在目标表中有所有 200 多行,并且我在 #dropprods 临时表中有 200 多个 ID。为什么?

** 编辑以更好地定义问题** * ** * ** * ** * * DELETE 语句不是问题。该问题与一组嵌套/命名事务有关。DELETE 语句在一个之下,INSERT 语句在另一个之下。这就是我所拥有的。这显然是错误的。我要做的是确保在我知道我会有一个很好的替代 INSERT 之前我不会提交 DELETE。这是我所做的: *EDITED T-SQL WITH SAVE TRANSACTION FIX * ** 这个 TSQL 现在可以工作了。

   -- CHANGED
   BEGIN TRANSACTION
   SAVE TRANSACTION process_orders
    BEGIN TRY
    -- detail level 
    DELETE lprods FROM [SQLServer].[WIP].[order].LiftProducts as lprods
     INNER JOIN #liftprods t on t.OrderId = lprods.OrderId
      AND t.OrderLiftId = lprods.OrderLiftId
      AND t.LiftProdId = lprods.LiftProdId;
           -- the rest of the deletes 
            --NOTE: No commit transaction here; saving it to the end
     END TRY
     BEGIN CATCH
        SELECT 
          ERROR_NUMBER() AS ErrorNumber, 
          ERROR_SEVERITY() AS ErrorSeverity,
          ERROR_MESSAGE() AS ErrorMessage;
         IF @@TRANCOUNT > 0
           ROLLBACK TRANSACTION process_orders;
       END CATCH

       BEGIN TRANSACTION 
        -- CHANGED
        SAVE TRANSACTION process_orders
       BEGIN TRY     
             -- CHANGED
                COMMIT TRANSACTION process_orders;     
       END TRY
       BEGIN CATCH
          SELECT 
            ERROR_NUMBER() AS ErrorNumber, 
            ERROR_SEVERITY() AS ErrorSeverity,
            ERROR_MESSAGE() AS ErrorMessage;
            IF @@TRANCOUNT > 0
              ROLLBACK TRANSACTION process_orders ;
       END CATCH 
4

1 回答 1

1

首先,您必须在 ROLLBACK TRANSACTION 之后删除事务名称。不允许回滚内部事务 - 只有最外面的事务可以回滚。

其次,SQL Server 忽略内部事务的提交(例如,锁等到最外面的事务提交后再释放)。所以你只需要一个没有事务名称的 COMMIT TRANSACTION。

如果您需要确保:

  • 如果删除成功,则开始插入,否则丢弃更改并
  • 如果这些插入成功,您接受更改,否则丢弃所有

如果您在 COMMIT 之前需要更加放心(例如:另一个开发人员在某些 SP 中编写插入代码,插入代码真的很大......等等),您可以使用您的 #liftprods 临时表(其中显然包含删除/插入的键) 并检查键是否与您认为应该插入的项目匹配。如果不是,请发出 RAISERROR('Some message', 16, 1) 这将回滚事务。

于 2012-10-27T21:40:38.293 回答