有2个表
CREATE TABLE dbo.[user] (
user_id INT NOT NULL IDENTITY PRIMARY KEY,
user_deleter INT REFERENCES [user] (user_id),
user_deleted DATETIME2
);
CREATE TABLE dbo.[project] (
project_id INT NOT NULL IDENTITY PRIMARY KEY,
project_owner INT NOT NULL REFERENCES [user] (user_id)
);
对于dbo。[user]有一个触发器应该删除一个(或多个)用户(这就是while和DELETERSTABLE的用途)
CREATE OR ALTER TRIGGER delete_user
ON dbo.[user]
INSTEAD OF DELETE
AS
BEGIN
SELECT * INTO DELETERSTABLE
FROM DELETED
WHILE (SELECT COUNT(*) FROM DELETERSTABLE) <> 0
BEGIN
DECLARE @id INT = (SELECT TOP 1 user_id FROM DELETERSTABLE)
DECLARE @deleted DATETIME2 = SYSDATETIME()
DECLARE @deleter INT = (SELECT TOP 1 dbo.[user].user_id FROM dbo.[user] INNER JOIN dbo.[usertype] ON dbo.[user].user_type = dbo.[usertype].type_id WHERE dbo.[usertype].type_name = 'ADMINISTRATOR')
UPDATE dbo.[user] SET user_deleted = @deleted, user_deleter = @deleter WHERE user_id = @id
DELETE FROM DELETERSTABLE WHERE user_id = @id
END
DROP TABLE DELETERSTABLE
END
GO
当我执行以下代码时:DELETE FROM dbo.[user]
它运行良好。但我正在尝试向触发器添加事务(因此它不仅删除2个用户而不是继续删除其他3个用户),就像我在下面做的尝试一样
CREATE OR ALTER TRIGGER delete_user
ON dbo.[user]
INSTEAD OF DELETE
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
SELECT * INTO DELETERSTABLE
FROM DELETED
WHILE (SELECT COUNT(*) FROM DELETERSTABLE) <> 0
BEGIN
DECLARE @id INT = (SELECT TOP 1 user_id FROM DELETERSTABLE)
DECLARE @deleted DATETIME2 = SYSDATETIME()
DECLARE @deleter INT = (SELECT TOP 1 dbo.[user].user_id FROM dbo.[user] INNER JOIN dbo.[usertype] ON dbo.[user].user_type = dbo.[usertype].type_id WHERE dbo.[usertype].type_name = 'ADMINISTRATOR')
UPDATE dbo.[user] SET user_deleted = @deleted, user_deleter = @deleter WHERE user_id = @id
DELETE FROM DELETERSTABLE WHERE user_id = @id
END
DROP TABLE DELETERSTABLE
END TRY
BEGIN CATCH
THROW 51001, 'CUSTOM ERROR: delete_user NOT executed', 1
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
IF @@TRANCOUNT > 0
COMMIT TRANSACTION
END
GO
当我执行以下代码时:DELETE FROM dbo.[user]
我收到下一个错误
DELETE语句与REFERENCE约束“FK__project__project__36FC065D”冲突。冲突发生在数据库“***”,表“dbo.project”,列“project_owner”
中
如何在保持第一个触发器的结构的同时仍然使用事务
答案 0 :(得分:0)
根本不需要WHILE
循环或任何这些变量。整个触发器可以更改为:
CREATE OR ALTER TRIGGER delete_user
ON dbo.[user]
INSTEAD OF DELETE
AS
BEGIN
UPDATE dbo.[user]
SET user_deleted = SYSDATETIME(),
user_deleter = (SELECT TOP 1 dbo.[user].user_id
FROM dbo.[user]
INNER JOIN dbo.[usertype] ON dbo.[user].user_type = dbo.[usertype].type_id
WHERE dbo.[usertype].type_name = 'ADMINISTRATOR') --Why do you want the deleter to be a random user?
WHERE user_id IN (SELECT user_id
from deleted);
END
GO
注意评论;你为什么TOP 1
没有ORDER BY
?您是否乐意将删除器标记为具有ADMINISTRATOR
类型的随机用户? (这似乎不是预期的逻辑)。
在这个问题下引用我的评论:
你不能在触发器中声明一个事务,因为它已经在一个事件中;如果触发器的任何部分失败,则回滚整个事务。
因此,您无需申报交易。