下面是表格Country
:
+------------------+-----------+
| COLUMN_NAME | DATA_TYPE |
+------------------+-----------+
| ID | int |
| Name | varchar |
| CapitalCity | varchar |
| Population | int |
| OfficialReligion | varchar |
| OfficialLanguage | varchar |
| DateEntered | datetime |
+------------------+-----------+
然后我有一个名为CountryRecord
的非常相似的表,它具有相同的列,然后是另外两个新的列:
+-------------------------+-----------+
| COLUMN_NAME | DATA_TYPE |
+-------------------------+-----------+
| ID | int |
| OriginalID | int |
| Name | varchar |
| CapitalCity | varchar |
| Population | int |
| OfficialReligion | varchar |
| OfficialLanguage | varchar |
| DateEntered | datetime |
| QueryType | varchar |
+-------------------------+-----------+
当插入,更新或在Country
,触发称为删除数据,也将插入行CountryRecord
,用于记录什么查询被用于数据的什么行所作的目的。触发器如下:
ALTER TRIGGER [dbo].[CountryRecord_Trigger]
ON [dbo].[Country]
AFTER UPDATE, INSERT, DELETE
AS
DECLARE @CountryID INT, @queryType VARCHAR(20);
--Update trigger
IF EXISTS (SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
BEGIN
SET @queryType = 'UPDATE';
SELECT @CountryID = ID FROM inserted i;
INSERT INTO CountryRecord (OriginalID, Name, CapitalCity, Population, OfficialReligion, OfficialLanguage, DateEntered, QueryType)
SELECT
ID, Name, CapitalCity, Population, OfficialReligion,
OfficialLanguage, DateEntered, @queryType
FROM
Country
WHERE
@CountryID = ID;
END
--Insert trigger
IF EXISTS (SELECT * FROM inserted) AND NOT EXISTS (SELECT * FROM deleted)
BEGIN
SET @queryType = 'INSERT';
SELECT @CountryID = ID FROM inserted i;
INSERT INTO CountryRecord (OriginalID, Name, CapitalCity, Population, OfficialReligion, OfficialLanguage, DateEntered, QueryType)
SELECT
ID, Name, CapitalCity, Population, OfficialReligion,
OfficialLanguage, DateEntered, @queryType
FROM
Country
WHERE
@CountryID = ID;
END
--Delete trigger
IF NOT EXISTS (SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
BEGIN
SET @queryType = 'DELETE';
SELECT @CountryID = ID FROM deleted d;
INSERT INTO CountryRecord (OriginalID, Name, CapitalCity, Population, OfficialReligion, OfficialLanguage, DateEntered, QueryType)
SELECT
ID, Name, CapitalCity, Population, OfficialReligion,
OfficialLanguage, DateEntered, @queryType
FROM
Country
WHERE
@CountryID = ID;
END
但是,当Insert和Update触发器工作时,Delete触发器不起作用。当我运行删除查询时,我只选择一行,所以我很确定删除查询不会选择多行(相反,似乎它没有选择任何内容,因为检查{{的当前标识) 1}}运行删除查询后显示它没有增加一个。)
更新:更改删除触发器以使用CountryRecord
而不是满足条件设置无法解决问题。相反,任何更新查询都将同时调用更新和删除触发器,而删除查询仍然无效。
更新2:为了检查我是否只影响了一行,我添加了针对每个触发器的选择查询以及ELSE
的打印 - 选择查询仅显示1行,而@CountryID
没有出现为空/空白。我也尝试改变列,考虑NOT NULL约束是否有任何影响,但它没有。
更新3:我现在有删除工作,虽然它只适用于单行删除。多行删除无法正常工作 - 例如,如果删除两条记录,则只有一行进入审计表。我还更新了插入和更新以使用类似的代码结构,因此它们也具有相同的多行问题。删除部分的代码段:
@CountryID
答案 0 :(得分:2)
删除不起作用的原因是因为该记录已从country
表中删除。所以你不能在那里选择它。
您需要从deleted
表中获取它。
您的其他两个查询也会引用触发器中的Country
表,这是个坏主意。您不应在查询中使用源表 - 您应该使用inserted
和deleted
代替。
考虑如何在一个查询中从插入和删除的表中编写一个查询,无论插入和删除多少条记录,都可以编写一个查询。如果你不放弃这个问题(它发生了很多),我会在这个答案中加上一个例子。
以下是一次性保存插入和更新的查询:
INSERT INTO CountryRecord (
Name,
CapitalCity,
Population,
OfficialReligion,
OfficialLanguage,
DateEntered,
QueryType)
SELECT
I.Name,
I.CapitalCity,
I.Population,
I.OfficialReligion,
I.OfficialLanguage,
GETDATE() As DateEntered,
CASE
WHEN EXISTS(SELECT * FROM DELETED D WHERE D.ID = I.ID)
THEN 'U' ELSE 'I'
END As QueryType
FROM INSERTED I
我遗漏了OriginalID
,因为人们不应该更新主键,而且,在这种情况下无法确定更新的内容。您只能在BEFORE触发器中执行此操作
这是一个捕获你的删除。我已经单独完成了这些,因此它们更容易理解,并且可能对大型记录集表现更好
INSERT INTO CountryRecord (
Name,
CapitalCity,
Population,
OfficialReligion,
OfficialLanguage,
DateEntered,
QueryType)
SELECT
D.Name,
D.CapitalCity,
D.Population,
D.OfficialReligion,
D.OfficialLanguage,
GETDATE() As DateEntered,
'D' As QueryType
FROM DELETED D
WHERE NOT EXISTS (SELECT * FROM INSERTED I WHERE I.ID = D.ID)
无论有多少行被更改,这些都可以使用
如果您想要实际检查更新中哪些列已更改,您可以再次在select语句中单独比较它们,或者您可以使用UPDATED()
函数
这是学校问题吗?因为触发器实际上是最后的手段,但人们仍坚持在学校教它们,即使它们几乎无关紧要。
什么是相关是我在此处发布的基于集合的解决方案