如何使用表的名称在表上删除

时间:2018-01-25 10:59:17

标签: sql-server temp-tables

我尝试编写一个触发器,在删除表之前检查某个位是否为真,如果该位为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;

希望这是足够的信息来获得答案,如果不是我以后再编辑它。

2 个答案:

答案 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而不是单独的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