Triggers 为什么这个触发器在使用插入的表时不起作用,但在用手动创建的表替换它时会起作用?

Triggers 为什么这个触发器在使用插入的表时不起作用,但在用手动创建的表替换它时会起作用?,triggers,sql-server-2012,Triggers,Sql Server 2012,我的问题域是一个人可以记录另一个人出席、迟到或缺席某项活动的状态。这样的录音可以修改,但版本历史记录是可以保存的 我在一个包含4个表的数据库中对其进行建模:Person、Activity、Registration和ObsoleteRegistration。注册有一个用于活动表的外键活动,两个用于Person表的外键registrant和registree,以及一个状态列,其值可以是present、late或缺席。废弃登记存储旧版本的登记记录。只有每个registree/activity对的最新注

我的问题域是一个人可以记录另一个人出席、迟到或缺席某项活动的状态。这样的录音可以修改,但版本历史记录是可以保存的

我在一个包含4个表的数据库中对其进行建模:Person、Activity、Registration和ObsoleteRegistration。注册有一个用于活动表的外键活动,两个用于Person表的外键registrant和registree,以及一个状态列,其值可以是present、late或缺席。废弃登记存储旧版本的登记记录。只有每个registree/activity对的最新注册存储在注册中。每个表都有一个id列作为主键

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

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
它在创建和触发时都不会产生错误,但它似乎没有像应该的那样更新存在和不存在列。它们的价值保持不变

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

我有什么常见的错误吗?有没有办法让我更好地理解幕后发生的事情


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

解决:事实证明,我只是因为疲劳而做了一些愚蠢的事情。 如果触发器是插入前触发器,那么它会工作得很好:因为它会检查注册表和插入表之间的差异,所以无法工作,因为在插入后触发器中,它们是相同的

当然,由于SQLServer不提供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
更新:如果触发器可以从更新触发器可以访问的已删除表中选择记录,则不会出现此问题,这表明最好将其建模为更新触发器。上述方法是可行的,但进行相应的更改和调整(例如将registree/activity设置为复合键)可以消除问题并简化实现


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

已删除表保存旧值,插入新值。使用两者来确定差异。我知道,问题是我的方法根本上是错误的:我试图使用插入查询作为更新查询。从我的问题中看不出这一点,因为我没有提到其他一些触发器,在判断它们无关之后,我做了一些小的调整,将registree/activity设置为复合键,并使用另一个表来存储旧的注册,然后将我的触发器再次建模为更新后的触发器,能够使用已删除和插入的表,因此无需访问实际表,一切都很顺利。