删除

时间:2018-04-24 13:13:39

标签: sql sql-server triggers

我正在使用after delete触发器,触发器的作用是在删除另一行时更新一行;但问题是,我更新行的方式是获取与删除的密钥相同的密钥:但是因为after delete触发器保留了假定的已删除行,并且由于密钥冲突而无法更新另一行,有没有办法明确删除该行,然后触发触发器(我不需要回滚)

所以这是我的触发器:

CREATE TRIGGER REORDONNE
AFTER DELETE  ON TEST1_TEST2
AS
BEGIN

DECLARE @oldOrder int

SELECT @oldOrder = ListOrder FROM deleted

UPDATE TEST1_TEST2
SET ListOrder=ListOrder-1
WHERE ListOrder > @oldOrder
END;

和我的表TEST1_TEST2是这样的:

enter image description here

我的桌子的钥匙是(LONSId,LOId,ListOrder)

然后我执行此请求:

从TEST1_TEST2删除 其中NSId = 13且Id = 1

问题是,当我尝试删除第4行时,触发器将尝试更新第5行并将ListOrder的值更改为1,但我得到KEY的错误,因为这2行将具有相同的键说:< / p>

  

Msg 2627,Niveau 14,État1,ProcédureREORDONNE,Ligne 19

     

Violation de la contrainte UNIQUE KEY'IX_TEST1_TEST2'。 Impossible d'insérerunecléendouble dans l'objet'dbo.TEST1_TEST2'。

我希望这很清楚

1 个答案:

答案 0 :(得分:0)

问题在于,您尝试重新编号所有行,其中ListOrder列值高于其中一个已删除的行 - 而不仅仅是那些共享相同的行{{> 1}}和LONSId 1 。因此,我们需要收紧LOId以更好地定位它。

虽然我们正在努力,但我们也可以使触发器多行删除也正确:

UPDATE

希望这里的逻辑清楚。我们计算出表中仍然存在哪些行应该受CREATE TRIGGER REORDONNE AFTER DELETE ON TEST1_TEST2 AS BEGIN ;With Ranges as ( select LONSId, LOId, ListOrder, COUNT(*) OVER (PARTITION BY LONSId,LOId ORDER BY ListOrder) as Cnt, LAG(ListOrder) OVER (PARTITION BY LONSId,LOId ORDER BY ListOrder desc) as NextListOrder from deleted ) update t set ListOrder= t.ListOrder- Cnt from TEST1_TEST2 t inner join Ranges r on t.LONSId = r.LONSId and t.LOId = r.LOId and t.ListOrder > r.ListOrder and (r.NextListOrder is null or r.NextListOrder > t.ListOrder) END; 中每一行的影响,并确保我们只针对那些行,考虑整个键。

(如果您的SQL Server版本不支持deleted,那么对SO的简单搜索应该会找到大量用于在旧版本上伪装它的示例。如果它不支持{{1或者LAG s那么你可以伪造那些但是真的,它们已经超出时间从这些机器升级了。)

1 E.g。在您的示例ROW_NUMBER中,您的触发器会尝试更新CTE大于delete from TEST1_TEST2 where NSId=13 and Id=1的所有行。您被告知(或至少其中一个)的实际冲突是针对具有当前密钥(2,2,2)的行,其中受到您的更新语句的影响,但是(2,2,1)不是删除的行,因此是重复键值。