我正在尝试编写我的第一个触发器。我有元素表。我里面的记录很少。很少有记录在 1 上具有复选框,在 0 上具有复选框的记录很少。
我正在尝试使触发器阻止删除在 1 (elm_intcolumn1
) 上具有复选框的记录。
触发器正在工作,但我无法删除复选框为 0 的记录。触发器阻止了我的元素上的所有记录。
ALTER TRIGGER [dbo].[test]
ON [dbo].[elements]
INSTEAD OF DELETE
AS
BEGIN
SELECT CASE
WHEN elm_intcolumn1 = 1
THEN 0
WHEN elm_intcolumn1 = 0
THEN 1
END
FROM elements
BEGIN
RAISERROR ('błąd', 16, 1)
ROLLBACK TRANSACTION
RETURN;
END
END
检查虚拟表DELETED
和INSERTED
-
CREATE TABLE dbo.[elements] (
id INT IDENTITY PRIMARY KEY,
elm_intcolumn1 BIT
)
GO
INSERT INTO dbo.[elements] (elm_intcolumn1)
VALUES (0), (1)
GO
ALTER TRIGGER dbo.test
ON dbo.[elements]
AFTER DELETE
AS
BEGIN
IF EXISTS(
SELECT 1
FROM DELETED
WHERE elm_intcolumn1 = 1
)
BEGIN
RAISERROR ('revert', 16, 1)
ROLLBACK TRANSACTION
END
END
GO
SELECT * FROM dbo.[elements]
DELETE dbo.[elements]
WHERE id = 2
删除第二条记录时:
Msg 50000, Level 16, State 1, Procedure test, Line 39
revert
Msg 3609, Level 16, State 1, Line 29
The transaction ended in the trigger. The batch has been aborted.
你把你的解决方案复杂化了。
首先 - 您不需要检查创建了哪个触发器的表,而是检查instead of delete
触发器上下文中可用的名为deleted
的特殊表。此表正好包含您尝试删除的记录。
其次 - 您的检查应该只是"删除表中是否有"elm_intcolumn1 = 1"的记录"。如果是 - 则抛出异常,如果没有这样的记录 - 则从表中删除deleted
中的所有记录。在这种情况下,您的表应该有一些主键(我假设它在下面的示例中被命名为 ID
)。
所以从字面上看,它是这样的:
if exists(select * from deleted where elm_intcolumn1 = 1)
begin
RAISERROR ('błąd', 16, 1)
ROLLBACK TRANSACTION
RETURN;
end
else
begin
delete from elements where ID in (select ID from deleted)
end
请注意,您必须在此触发器中从表中显式删除记录,因为它是instead of delete
,而不是after delete
。
或者,您可以将触发器类型更改为after delete
这样就不需要在条件分支中显式删除else
这样