【问题标题】:instead of trigger and keeping unique values in a column而不是触发并在列中保留唯一值
【发布时间】:2015-11-03 08:17:20
【问题描述】:

我有一个带有代替触发器的表(如下所示)(代码如下所示)

我的表:

 ID    directory    manager
 ---------------------------
 1     C:\Blah\     Bob
 2     C:\Blob\     Dave

ID 是主键。

我的触发器处理插入、更新和删除。删除不是问题。我希望在我的表中插入或更新记录以确保目录是唯一的。做这个的最好方式是什么? ID 必须作为主键保存。

我的触发代码(精简),

create trigger trMyTable on MyTable
instead of insert, update, delete
as
begin
    declare @permission bit

    if exists(select * from inserted)
    begin
        if exists(select * from deleted)
        begin                               -- its an update query
            update MyTable
            set directory = inserted.directory,
                manager = inserted.manager
            from inserted 
            inner join MyTable on inserted.ID = MyTable.ID;
        end             
        else
            insert into MyTable(directory, manager) 
                select 
                    directory, manager 
                from inserted;
    end
end

【问题讨论】:

  • “确保目录是唯一的” - 那么为什么不对该列应用 unique 约束呢?
  • 对不起,我对sql知之甚少。因此,在我的表设置中,我可以对目录列应用唯一约束,然后我的代码就可以了吗?
  • 是的,请参阅Create Unique Constraints。还有其他类型的约束(外键、检查,并且您已经熟悉主键约束),如果它们能够完成这项工作,您应该尝试使用它们而不是编写触发器。
  • ALTER TABLE MyTable ADD CONSTRAINT ux_MyTable_Directory UNIQUE (directory)

标签: sql sql-server triggers sql-server-2012


【解决方案1】:

到目前为止,最好和最简单的方法是 DavidG 建议的唯一约束:

ALTER TABLE MyTable ADD CONSTRAINT ux_MyTable_Directory UNIQUE (directory)

要作为触发器完成,您可以执行以下操作以确保满足您的业务需求,但除非有其他原因需要触发器(审核或其他),否则请务必考虑 UNIQUE 约束。即使您将触发器用于安全或审计,我仍然会使用 UNIQUE 约束,因此您可以将触发器更改为 AFTER 代替 INSTEAD OF,这样您就可以只执行这些功能,而不是处理所有数据操作。

create trigger trMyTable on MyTable
instead of insert, update, delete
as
begin
    declare @permission bit

    -- Verify no duplicate
    if exists(
        select *
        from inserted
        where exists (
            select *
            from MyTable
            where directory = inserted.directory
                and id <> inserted.id
        ))
    begin
        raiserror('Duplicate directory', 15, 99)
    end
    else
    begin

        -- Perform data changes
        if exists(select * from inserted)
        begin
            if exists(select * from deleted)
            begin                               -- its an update query
                update MyTable
                set directory = inserted.directory,
                    manager = inserted.manager
                from inserted 
                inner join MyTable on inserted.ID = MyTable.ID;
            end             
            else
                insert into MyTable(directory, manager) 
                    select 
                        directory, manager 
                    from inserted;
        end
        else
        begin
            delete MyTable where id in (select id from deleted)
        end
    end
end

【讨论】:

    猜你喜欢
    • 2018-03-25
    • 1970-01-01
    • 2020-04-15
    • 2018-09-07
    • 2018-11-21
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    相关资源
    最近更新 更多