SQL Server触发活动卡

时间:2018-12-04 11:01:25

标签: sql sql-server database triggers

我有下表:

  • 卡(ID卡,IDPerson,余额,有效)
  • 人员(IDPerson)

每次插入新卡时,我都需要检查该卡是否已经属于某个人。如果是这样,我需要将active更改为false,新卡必须收到前一张卡的余额,并且状态必须为true。

select count(c.IDPerson) 
from cards c, inserted i 
where c.IDPerson = i.IDPerson;

if @@ROWCOUNT > 0
begin
    print'this card already exists'

    select c.IDPerson, c.Balance, c.Active
    INTO #tmp
    FROM Cards c, inserted i
    where c.IDCard = i.IDCard

    update Cards
    set Active = 0
    from #tmp
    where #tmp.IDPerson = Cards.IDPerson;
end

当我在卡表中插入新记录时,旧卡确实变为假(0),但是新卡也保持活动状态,等于假。 这是在插入卡片后的表格中。

有人可以告诉我如何解决该问题吗?

2 个答案:

答案 0 :(得分:2)

尽管触发器在事务中运行,但我认为它仍然能够更新自身。

当您更新INSERTED.IDPERSON = CARD.IDPERSON的位置时-这包括您已插入的记录;因此所有记录都更新为Active = false。

相反,您应该这样做

update Cards
set Active = 0
from #tmp
where #tmp.IDPerson = Cards.IDPerson
AND Cards.IDCARD != #tmp.IDCARD    --This is the new condition

我已经创建了一份我相信您在此DBFiddle Link

中询问的内容的副本

用户marc_s也正确地说您应该在此处使用JOIN语法。您的整个操作可以用一个简洁得多的语句完成

UPDATE c
SET c.Active = 0
FROM Cards c
INNER JOIN Inserted i
ON i.IDPERSON = c.IDPERSON
AND i.IDCARD != c.IDCARD

答案 1 :(得分:0)

if是不合适的。请记住,触发器可以同时处理多行。

显式join执行所需的过滤。这有点复杂,但是您可以使用两个join来做到这一点:

update c2
    set Active = (case when c2.IDCard = i.IDCard then 1 else 0 end)
    from Cards c 
         inserted i
         on c.IDCard = i.IDCard join
         Cards c2
         on c.IDPerson = c2.IDPerson;