SQL Server 2008触发多次插入时无法正常工作

时间:2010-05-03 17:40:05

标签: sql sql-server sql-server-2008 triggers

我有以下触发器;

CREATE TRIGGER trFLightAndDestination
ON checkin_flight
AFTER INSERT,UPDATE
AS
BEGIN
    IF NOT EXISTS
    (
                    SELECT 1 
            FROM Flight v
            INNER JOIN Inserted AS i ON i.flightnumber = v.flightnumber
            INNER JOIN checkin_destination AS ib ON ib.airport = v.airport
            INNER JOIN checkin_company AS im ON im.company = v.company
            WHERE i.desk = ib.desk AND i.desk = im.desk
    )
    BEGIN
        RAISERROR('This combination of of flight and check-in desk is not possible',16,1)
        ROLLBACK TRAN       
    END
END

我希望触发器做的是在添加checkin_flight的新记录时检查表Flight,checkin_destination和checkin_company。 checkin_flight的每条记录都包含一个乘客需要办理登机手续的航班号和办公桌号码。 checkin_destination和checkin_company表包含有关限于某些登记台的公司和目的地的信息。在向checkin_flight添加记录时,我需要来自航班表的信息以获取具有插入的航班号的目的地和航班公司。需要根据航班,目的地和公司的可用登记组合检查此信息。

我正在使用如上所述的触发器,但是当我尝试插入错误的组合时,触发器允许它。我在这里缺少什么?

编辑1: 我正在使用以下多个插入语句

INSERT INTO checkin_flight VALUES (5315,3),(5316,3),(5316,2)
//5315 is the flightnumber, 3 is the desknumber to checkin for that flight

编辑2: 测试了单行插入是不可能的,然后错误被抛出正确。所以它是多重插入,似乎给出了问题。

4 个答案:

答案 0 :(得分:1)

我不确定您的业务逻辑,但您需要检查查询是否正确。

您的问题是IF NOT EXISTS,如果INSERTED中3行中的1行的条件为真,则它不存在。您需要将其转换为查找问题行并使用IF EXISTS然后输出错误。

但是,在触发器中,出错的最佳方法是:

RAISERROR()
ROLLBACK TRANSACTION
RETURN

我有点怀疑缺少RETURN是你的问题,但最好在触发器出错时包含三个R

答案 1 :(得分:1)

问题是您的逻辑允许任何包含至少一个有效值集的插入。只有插入的记录的所有无效,而不是插入的记录的任何无效时,它才会失败。

将“IF NOT EXISTS(...)”更改为“IF EXISTS(...)”语句并更改SELECT语句以返回无效航班。

例如:

IF EXISTS
(
                SELECT 1 
        FROM Flight v
        INNER JOIN Inserted AS i ON i.flightnumber = v.flightnumber
        LEFT JOIN checkin_destination AS ib ON ib.airport = v.airport
             AND i.desk = ib.desk
        LEFT JOIN checkin_company AS im ON im.company = v.company
             AND i.desk = im.desk
        WHERE (im.desk IS NULL OR ib.desk IS NULL)
)
BEGIN
    RAISERROR('This combination of of flight and check-in desk is not possible',16,1)
    ROLLBACK TRAN       
END

答案 2 :(得分:1)

inserted表可以包含多行,因此触发器中的所有逻辑必须能够应用于所有行。这个想法触发器必须每次触发一次效果是一个常见的误解WRT触发器。 SQL Server倾向于合并对触发器的调用,以便在同一事务中发生时提高性能。

要解决此问题,您可以从插入的COUNT()开始,并将其与匹配条件的COUNT()进行比较,如果不匹配则引发错误。

答案 3 :(得分:1)

问题是如果只有一个插入的记录是正确的,则条件为真。您必须检查所有记录是否正确,例如:

if (
  (
    select count(*) from inserted
  ) = (
    select count(*) from flight v
    inner join inserted i ...
  )
) ...