如何使用 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 而不是单独的 INSERTUPDATE 语句:

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