我尝试编写一个触发器,在删除表之前检查某个位是否为真,如果该位为false则将其设置为非活动状态。我的触发器是:
DELETE Contacts
FROM Contacts
INNER JOIN deleted ON Contacts.ContactID = deleted.ContactID
WHERE deleted.AllowDelete = 1
UPDATE Contacts
SET Active = 0
FROM Contacts
INNER JOIN deleted on Contacts.ContactID = deleted.ContactID
WHERE deleted.allowDelete = 0
联系人是其他人试图删除的表格。但是,在必要的每个表上使用此触发器似乎效率低下,因此我尝试使用存储过程对其进行规范化。
这个想法是用表名作为变量来执行SP,并将删除的表放入temptable中。现在触发器看起来像这样:
SELECT *
INTO #deleted
FROM deleted
DROP TABLE #deleted
SP看起来像这样:
ALTER PROCEDURE [dbo].[OnDeleteTrigger]
-- Add the parameters for the stored procedure here
@TableToDeleteFrom nvarchar(max) = ''
AS
BEGIN
SET NOCOUNT ON;
DECLARE
DELETE Contacts
FROM Contacts
INNER JOIN #deleted ON Contacts.ContactID = #deleted.ContactID
WHERE #deleted.AllowDelete = 1
Update Contacts
SET Active = 0
FROM Contacts
INNER JOIN #deleted ON Contacts.ContactID = #deleted.ContactID
WHERE #deleted.AllowDelete = 1
END
删除的temptable似乎工作正常,虽然我无法测试它,因为我无法找到从表名中获取表dbo的方法,以替换所有' Contacts& #39;
希望这是足够的信息来获得答案,如果不是我以后再编辑它。
答案 0 :(得分:0)
我想你想要使用触发器"而不是": https://technet.microsoft.com/en-us/library/ms175521(v=sql.105).aspx
CREATE TABLE Contacts
(
id int identity(1,1) primary key clustered,
[name] varchar(50),
isactive bit not null default(1),
SoftDeletion bit not null default(1)
)
insert into Contacts([name]) values ('my'),('myself'),('I');
insert into Contacts([name],SoftDeletion) values ('Killable', 0);
GO
CREATE TRIGGER trgInsteadOfDelete ON Contacts
INSTEAD OF DELETE
AS
BEGIN
UPDATE Contacts
set isactive = 0
where
SoftDeletion = 1
and
id in (SELECT ID from deleted);
DELETE FROM Contacts
WHERE
softdeletion = 0
AND
id in (SELECT ID from deleted);
END
GO
SELECT * from Contacts;
DELETE FROM Contacts;
SELECT * from Contacts;
答案 1 :(得分:0)
在具有静态SQL的每个表上使用单独的触发器更有效,尽管不适合代码重用。其他表将具有与ContactID不同的主键列名,因此您需要传递该名称以及表名。
如果所需的表表都具有标准列Active和AllowDelete,则可以在部署期间动态创建所需的触发器,而不是在运行时创建动态SQL。以下是此技术的示例,使用MERGE
而不是单独的INSERT
和UPDATE
语句:
CREATE TABLE dbo.Contacts(
ContactID int NOT NULL CONSTRAINT PK_Contacts PRIMARY KEY
, Active bit NOT NULL
, AllowDelete bit NOT NULL
);
CREATE TABLE dbo.Users(
UserID int NOT NULL CONSTRAINT PK_Users PRIMARY KEY
, Active bit NOT NULL
, AllowDelete bit NOT NULL
);
INSERT INTO dbo.Contacts VALUES(1, 1, 0);
INSERT INTO dbo.Contacts VALUES(2, 1, 0);
INSERT INTO dbo.Contacts VALUES(3, 1, 1);
INSERT INTO dbo.Contacts VALUES(4, 1, 1);
INSERT INTO dbo.Users VALUES(1, 1, 0);
INSERT INTO dbo.Users VALUES(2, 1, 0);
INSERT INTO dbo.Users VALUES(3, 1, 1);
INSERT INTO dbo.Users VALUES(4, 1, 1);
GO
CREATE PROC dbo.CreateSoftDeleteTrigger
@SchemaName sysname
, @TableName sysname
, @JoinCriteria nvarchar(MAX)
AS
SET NOCOUNT ON;
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'CREATE TRIGGER ' + QUOTENAME(N'TRD_' + @TableName) + N'
ON ' + QUOTENAME(@SchemaName) + N'.' + QUOTENAME(@TableName) + N'
INSTEAD OF DELETE
AS
SET NOCOUNT ON;
MERGE ' + QUOTENAME(@SchemaName) + N'.' + QUOTENAME(@TableName) + N' AS target
USING deleted ON ' + @JoinCriteria + N'
WHEN MATCHED AND deleted.AllowDelete = 1 THEN DELETE
WHEN MATCHED AND deleted.AllowDelete = 0 THEN UPDATE SET Active = 0;'
EXECUTE(@SQL);
GO
EXEC dbo.CreateSoftDeleteTrigger
@SchemaName = N'dbo'
, @TableName = N'Contacts'
, @JoinCriteria = N'target.ContactID = deleted.ContactID';
EXEC dbo.CreateSoftDeleteTrigger
@SchemaName = N'dbo'
, @TableName = N'Users'
, @JoinCriteria = N'target.UserID = deleted.UserID ';
GO
--soft delete test
DELETE FROM dbo.Contacts WHERE ContactID = 1;
SELECT * FROM Contacts;
--hard delete test
DELETE FROM dbo.Users WHERE UserID = 4;
SELECT * FROM Users;
GO