【发布时间】:2018-05-07 02:21:01
【问题描述】:
下表为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
但是,虽然插入和更新触发器起作用,但删除触发器却不起作用。当我运行删除查询时,我只选择一行,所以我相当确定删除查询没有选择多于一行(相反,它似乎什么也没选择,因为检查了@987654328 的当前身份@ 运行删除查询后显示它没有增加一)。
更新:将删除触发器更改为使用 ELSE 而不是满足条件集并不能解决问题。相反,任何更新查询都会调用更新和删除触发器,而删除查询仍然无效。
更新 2: 只是为了检查我只影响了一行,我为每个触发器添加了选择查询以及@CountryID 的打印 - 选择查询仅显示 1 行,而@CountryID 没有出现为空/空白。我还尝试更改列,考虑 NOT NULL 约束是否有任何影响,但它没有。
更新 3: 我现在已经让 Delete 工作了,虽然它只适用于单行删除。多行删除无法正常工作 - 例如,如果我删除两条记录,则只有一行进入审计表。我还更新了 Insert 和 Update 以使用类似的代码结构,因此它们也有相同的多行问题。删除部分的代码sn-p:
SET @queryType = 'DELETE';
SELECT CountryID = ID FROM deleted;
INSERT INTO CountryRecord (OriginalID, Name, CapitalCity, Population, OfficialReligion, OfficialLanguage, DateEntered, QueryType)
SELECT ID, Name, CapitalCity, Population, OfficialReligion, OfficialLanguage, DateEntered, @queryType FROM deleted WHERE @CountryID = ID;
DECLARE @auditID int;
SET @auditID = SCOPE_IDENTITY();
UPDATE CountryRecord SET QueryType = @queryType WHERE ID = @auditID;
【问题讨论】:
-
您正在犯第一个触发错误:假设
INSERTED和DELETED只有一行 - 他们没有。此外,您的审计表可能不需要所有这些列 -
我在
INSERTED和DELETED的选择查询中添加了 - 结果只显示了 1 行。目前我所做的只是插入、更新和删除具有相同 ID 的同一行。我还做了一个PRINT的@CountryID- 在每个触发器中,@CountryID不是空/空白。 -
这很好,但您应该尝试修复已经存在其他错误的代码。如果你得到这个工作,你仍然需要修复多行错误。您想要做的可以在 one 插入语句中实现。 stackoverflow上有很多例子。我会找到一个
-
您的删除不起作用的原因是该记录已从
country表中删除。您需要从deleted表中获取它。你的另外两个也一样。在触发器中引用源表是个坏主意。 -
想一想如何从
inserted和deleted表中编写一个查询,在一个查询中完成您想要的所有操作,无论inserted中有多少记录和deleted
标签: sql sql-server triggers sql-server-2014 sql-delete