我的问题域是一个人可以将另一个人的在场状态(现在,迟到或缺席)记录到某个活动的域。可以修改此类录制,但保留版本历史记录。
我在一个包含4个表格的数据库中对其进行了建模:Person
,Activity
,Registration
和ObsoleteRegistration
。 Registration
具有activity
表的外键(Activity
),registrant
表的两个外键(registree
和Person
),以及state
列,其值可以是present
,late
或absent
。 ObsoleteRegistration
存储旧版Registration
条记录。 (只有每个registree
/ activity
对的最新注册都存储在Registration
内。每个表都有一个id
列作为主键。
由于询问活动存在和缺席总数的查询比插入注册的查询频繁得多,因此我将多余的presences
和absences
列添加到了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
它不会产生任何错误(既不会在创建时也不会在触发器上),但它似乎不会更新presences
和absences
列。 (他们的价值保持不变)
然而,令人惊讶的是,使用手动创建的表替换inserted
表,该表包含插入的表应在插入中包含的相同数据,这会导致一切正常工作。
我正在制造什么常见错误?有什么方法可以让我更好地理解幕后发生的事情吗?
如果细节不足,请告诉我,我可以详细说明。
答案 0 :(得分:0)
解决了:因为经常发现,我只是因疲倦而做蠢事。
如果它是BEFORE INSERT触发器,触发器将完美地工作:由于它检查Registration
和inserted
表之间的差异,它无法工作,因为在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查询和触发器。