SQL触发器无法按预期工作

时间:2013-02-14 05:05:09

标签: sql triggers

我有一个SQL触发器,如下所示

GO
create trigger ExpDateCheckCard
On Card 
FOR Insert, Update
As
Declare @expDate as DateTime
Select @expDate = inserted.ExpirationDate from inserted
if (YEAR(@expDate) < 1971 )
BEGIN
     UPdate Card set ExpirationDate = '1900-01-01 00:00:00' FROM Card, inserted
                                where inserted.RecordID = Card.RecordID
END

如果我在触发器运行时插入/更新的每个记录的触发器是正确的,它将检查该记录的ExpirationDate列中的YEAR,如果该值小于1971,那么它将使用日期更新它更新查询。

奇怪的是它没有按预期工作。

if条件似乎不起作用。

此特定触发器有什么问题。

3 个答案:

答案 0 :(得分:3)

- 你写这个触发器的方式肯定存在根本性的错误。

SQL Server(假设你正在使用的)将触发每行不会触发一次(包括你自己在内的很多人)似乎认为 - 触发器被激活每批次,这可能会更新或者一次插入10,20,50行。

因此,触发器中的Inserted伪表可以(并且将!)包含多行 - 在这种情况下 - 您的语句究竟选择了什么?

Select @expDate = inserted.ExpirationDate from inserted

要么你只得到一个randon行(50个)并处理(并忽略所有49个其他行),否则你会收到错误....

你需要记住你的触发器 - 你必须总是假设Inserted(和Deleted)将包含多行!

因此,您需要将触发器更改为:

CREATE TRIGGER ExpDateCheckCard
ON dbo.Card 
FOR Insert, Update
AS
  UPDATE dbo.Card 
  SET ExpirationDate = '1900-01-01 00:00:00' 
  FROM dbo.Card c
  INNER JOIN inserted i ON i.RecordID = c.RecordID
  WHERE YEAR(i.ExpirationDate) < 1971

我还将旧式JOIN语法(以逗号分隔的表格列表)更改为自1992年以来一直存在的ANSI标准 - 请不要使用逗号 - 分隔的表格列表!使用正确的 ANSI JOIN 。有关更多背景信息,请参阅此博客文章:Bad habits to kick : using old-style JOINs

答案 1 :(得分:0)

试试这个:

create trigger ExpDateCheckCard
    On Card 
    FOR Insert, Update
    As
    BEGIN
    Declare @expDate as DateTime
    Select @expDate = inserted.ExpirationDate from inserted
    if (YEAR(@expDate) < 1971 ) Begin

         UPdate Card set ExpirationDate = '1900-01-01 00:00:00' FROM Card, inserted
                                    where inserted.RecordID = Card.RecordID
    end
    END

答案 2 :(得分:0)

您必须尝试此代码

CREATE TRIGGER ExpDateCheckCard AFTER INSERT,Update ON Card
   FOR EACH ROW

   Declare @expDate as DateTime
   Select @expDate = inserted.ExpirationDate from inserted
   if (YEAR(@expDate) < 1971 )
   BEGIN
      update Card 
      set ExpirationDate = '1900-01-01 00:00:00' FROM Card, inserted
      where inserted.RecordID = Card.RecordID
   END