如何使用 table 的名称删除 table
How to DELETE on a table using the table's name
我正在尝试编写一个触发器,在删除 table 之前检查某位是否为真,如果该位为假,则将其设置为非活动状态。我的触发器是这样的:
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
联系人是 table 某人试图从中删除的联系人。但是,在每个需要的 table 上使用此触发器似乎效率低下,因此我尝试使用存储过程对其进行规范化。
想法是用 tablename 作为变量执行 SP,并将删除的 table 放入 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 似乎工作正常,虽然我还不能测试它,因为我找不到从 table 获取 table dbo 的方法名称,替换所有 'Contacts'.
希望这些信息足以获得答案,否则我稍后会对其进行编辑。
我猜你想使用触发器 "instead of":
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;
在每个 table 上使用静态 SQL 单独的触发器效率更高,尽管它不利于代码重用。其他 table 的主键列名称与 ContactID 不同,因此您需要传递该名称以及 table 名称。
由于所需的 tables tables 都具有标准列 Active 和 AllowDelete,您可以在部署期间动态创建所需的触发器,而不是在 [=22= 处动态创建 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
我正在尝试编写一个触发器,在删除 table 之前检查某位是否为真,如果该位为假,则将其设置为非活动状态。我的触发器是这样的:
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
联系人是 table 某人试图从中删除的联系人。但是,在每个需要的 table 上使用此触发器似乎效率低下,因此我尝试使用存储过程对其进行规范化。
想法是用 tablename 作为变量执行 SP,并将删除的 table 放入 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 似乎工作正常,虽然我还不能测试它,因为我找不到从 table 获取 table dbo 的方法名称,替换所有 'Contacts'.
希望这些信息足以获得答案,否则我稍后会对其进行编辑。
我猜你想使用触发器 "instead of": 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;
在每个 table 上使用静态 SQL 单独的触发器效率更高,尽管它不利于代码重用。其他 table 的主键列名称与 ContactID 不同,因此您需要传递该名称以及 table 名称。
由于所需的 tables tables 都具有标准列 Active 和 AllowDelete,您可以在部署期间动态创建所需的触发器,而不是在 [=22= 处动态创建 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