为什么这个触发器不会使用inserted表工作,但是在用手动创建的表替换它时会是什么?

时间:2015-09-06 18:05:05

标签: triggers sql-server-2012

我的问题域是一个人可以将另一个人的在场状态(现在,迟到或缺席)记录到某个活动的域。可以修改此类录制,但保留版本历史记录。

我在一个包含4个表格的数据库中对其进行了建模:PersonActivityRegistrationObsoleteRegistrationRegistration具有activity表的外键(Activity),registrant表的两个外键(registreePerson),以及state列,其值可以是presentlateabsentObsoleteRegistration存储旧版Registration条记录。 (只有每个registree / activity对的最新注册都存储在Registration内。每个表都有一个id列作为主键。

由于询问活动存在和缺席总数的查询比插入注册的查询频繁得多,因此我将多余的presencesabsences列添加到了Activity表中,并寻求用触发器更新它们。我想出了以下代码:

CREATE TRIGGER UpdateActivitypresencestatistics
ON Registrations
AFTER INSERT
AS
BEGIN
    UPDATE Activity
    SET
        presences = presences + Updates.presencesToAdd + Updates.absencesToBeConvertedInpresences,
        absences  = absences + Updates.absencesToAdd - Updates.absencesToBeConvertedInpresences
    FROM
    (
        SELECT
            inserted.activity AS activity,
            SUM (CASE WHEN (Present.state IS NULL) AND (inserted.state = 'present' OR inserted.state = 'late') THEN 1 ELSE 0 END) AS presencesToAdd,
            SUM (CASE WHEN (Present.state = 'absent') AND (inserted.state = 'present' OR inserted.state = 'late')THEN 1 ELSE 0 END) AS absencesToBeConvertedInpresences,
            SUM (CASE WHEN (Present.state IS NULL) AND (inserted.state = 'absent') THEN 1 ELSE 0 END) AS absencesToAdd
        FROM Registrations AS Present
        RIGHT OUTER JOIN inserted
        ON 
            Present.registree = inserted.registree
            AND Present.activity = inserted.activity
        GROUP BY
            inserted.activity
    ) Updates
    WHERE 
        Activity.id = Updates.activity
END

它不会产生任何错误(既不会在创建时也不会在触发器上),但它似乎不会更新presencesabsences列。 (他们的价值保持不变)

然而,令人惊讶的是,使用手动创建的表替换inserted表,该表包含插入的表应在插入中包含的相同数据,这会导致一切正常工作。

我正在制造什么常见错误?有什么方法可以让我更好地理解幕后发生的事情吗?

如果细节不足,请告诉我,我可以详细说明。

1 个答案:

答案 0 :(得分:0)

解决了:因为经常发现,我只是因疲倦而做蠢事。 如果它是BEFORE INSERT触发器,触发器将完美地工作:由于它检查Registrationinserted表之间的差异,它无法工作,因为在AFTER INSERT触发器中它们是相同的。

当然,由于SQL Server不提供BEFORE INSERT触发器,因此必须将其更改为INSTEAD OF触发器,并手动插入。

以下代码有效:

CREATE TRIGGER UpdateActivitypresencestatistics
ON Registrations
INSTEAD OF INSERT
AS
BEGIN
    UPDATE Activity
    SET
        presences = presences + Updates.presencesToAdd + Updates.absencesToBeConvertedInpresences,
        absences  = absences + Updates.absencesToAdd - Updates.absencesToBeConvertedInpresences
    FROM
    (
        SELECT
            inserted.activity AS activity,
            SUM (CASE WHEN (Present.state IS NULL) AND (inserted.state = 'present' OR inserted.state = 'late') THEN 1 ELSE 0 END) AS presencesToAdd,
            SUM (CASE WHEN (Present.state = 'absent') AND (inserted.state = 'present' OR inserted.state = 'late')THEN 1 ELSE 0 END) AS absencesToBeConvertedInpresences,
            SUM (CASE WHEN (Present.state IS NULL) AND (inserted.state = 'absent') THEN 1 ELSE 0 END) AS absencesToAdd
        FROM Registrations AS Present
        RIGHT OUTER JOIN inserted
        ON 
            Present.registree = inserted.registree
            AND Present.activity = inserted.activity
        GROUP BY
            inserted.activity
    ) Updates
    WHERE 
        Activity.id = Updates.activity

    INSERT INTO Registrations
    SELECT registrant, registree, status, activity -- Explicit list necessary because of the identity primary key column
    FROM inserted
END

更新:如果触发器可以从已删除的表中选择UPDATE触发器可以访问的记录,则不会出现此问题,这表明最好将其建模为UPDATE触发器。上述工作,但进行此类更改(并相应调整,例如使注册表/活动成为复合键)消除了问题并简化了实施。

如果您遇到同样的问题,请考虑使用UPDATE查询和触发器。