我正在使用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是这样的:
我的桌子的钥匙是(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'。
我希望这很清楚
答案 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)不是删除的行,因此是重复键值。