【问题标题】:How can I update a column in SQL Server using a trigger如何使用触发器更新 SQL Server 中的列
【发布时间】:2019-04-01 16:32:01
【问题描述】:

我正在尝试在 SQL Server Management Studio 中创建一个触发器,当在同一个表中更新了单独的列时,该触发器会将列值增加 1。

当更新脚本运行时,我们要更新的列的值变为 NULL

我的示例是,当我更改客户的地址时,我希望在每次更改地址时增加一列,即 NoOfAddressess = 1、2、3 等...

这是我正在编写的 SQL 代码

ALTER TRIGGER trg_customeraudit 
ON tblCustomer
AFTER UPDATE, DELETE, INSERT
AS
    INSERT INTO dbo.CustomerDetailsAudit 
    VALUES (CURRENT_USER, CURRENT_TIMESTAMP, 
            (SELECT CustomerID FROM inserted), 
            (SELECT CustomerAddress FROM deleted), 
            (SELECT CustomerAddress FROM inserted),
            (SELECT CustomerPostcode FROM deleted), 
            (SELECT CustomerPostcode FROM inserted), 
            (SELECT NumberOfChangedAddresses FROM dbo.CustomerDetailsAudit)  
           )

    IF ((SELECT CustomerAddress FROM inserted) = 
        (SELECT CustomerAddress FROM deleted) OR 
        (SELECT CustomerPostcode FROM deleted) = 
        (SELECT CustomerPostcode FROM inserted))
    BEGIN
        RAISERROR ('You must enter both a new postcode and address',16,10)
        ROLLBACK TRANSACTION
    END 
ELSE
BEGIN 
    PRINT 'Transaction successful'
    WHERE CustomerID = (SELECT CustomerID from inserted)
END

IF UPDATE (CustomerName)
BEGIN
    RAISERROR ('You cannot change the customer name', 16, 10)
    ROLLBACK
END

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow。你有什么问题?
  • 您的触发器有 MAJOR 缺陷,您似乎认为它会被 每行调用一次 - 事实并非如此。触发器将每条语句触发一次,因此如果您的INSERT 导致此触发器触发插入 25 行,您将触发触发器一次和@987654323 @ 伪表将包含 25 行。您的代码将从Inserted 中选择这 25 行中的哪一行?它是不确定的,您将获得任意行,而您将忽略所有其他行。您需要重写触发器以考虑到这一点!
  • 如果您的语句影响多行,那么像SELECT CustomerID FROM inserted 这样的语句将从 5、10 或inserted 中的 25 个条目,忽略所有其他条目。无法保证会选择哪一个 - 所以基本上,只要没有人一次插入、更新或删除多行,所有这些代码都可以工作。如果发生这种情况,此代码将执行您期望的操作!你需要完全重写你的代码
  • 你只是突然自找麻烦,不知何故用户或程序开始更新多行......
  • 如果您绝对确定不会超过一行,那么添加对行数的检查并使用RaIsErrorThrow 明确告知那些后来发现他们试图执行不可接受的声明的人。 (if ( select Count(*) from inserted ) > 1 RaIsError( 'FooTable_Insert: No more than one row may be processed.', 25, 42 ) with log)

标签: sql-server tsql triggers


【解决方案1】:

根据此数据上发生的其他事情,触发器可能是一种非常低效的处理方法,但这是一种可能的解决方案。

1.设置

首先创建一个用于测试的表。

create table test_table (
      MyPrimaryKey int primary key clustered not null identity(1, 1)
    , SomeColumn varchar(255) not null
    , SomeColumnCounter int null
);
go

现在,添加一个触发器以将计数器初始化为 1。这可以通过默认约束来处理或在应用程序级别设置,但也可以通过触发器来完成。

-- this trigger will set the counter to 1 when a record is first added
-- doesn't need to be a trigger, but since the question was on triggers
create trigger trg_test_table_insert
    on test_table
    after insert
as
    update tt
        set tt.SomeColumnCounter = 1
    from
        test_table as tt
    inner join
        Inserted as i
        on
            tt.MyPrimaryKey = i.MyPrimaryKey;
go

现在,添加一个触发器,该触发器将检查指定列上的更改并在需要时增加计数器。

-- this trigger will increment the counter by 1 if 'SomeColumn' changed
-- doesn't handle nulls so will need to be modified depending on schema
create trigger trg_test_table_update
    on test_table
    after update
as
    update tt
        set tt.SomeColumnCounter = tt.SomeColumnCounter + 1
    from
        Inserted as i -- new version of the record
    inner join
        Deleted as d -- old version of the record
        on
            i.MyPrimaryKey = d.MyPrimaryKey
            and i.SomeColumn <> d.SomeColumn
    inner join
        test_table as tt
        on
            tt.MyPrimaryKey = i.MyPrimaryKey
go

2。测试

添加一些测试数据。

insert into test_table (SomeColumn)
values ('abc'), ('def');
go

现在我们有了:

MyPrimaryKey    SomeColumn  SomeColumnCounter
1               abc         1
2               def         1

更新而不改变任何东西:

update tt
    set tt.SomeColumn = 'abc'
from
    test_table as tt
where
    tt.MyPrimaryKey = 1

我们还有:

MyPrimaryKey    SomeColumn  SomeColumnCounter
1               abc         1
2               def         1

真正改变某些东西的更新:

update tt
    set tt.SomeColumn = 'abbc'
from
    test_table as tt
where
    tt.MyPrimaryKey = 1

现在我们有了:

MyPrimaryKey    SomeColumn  SomeColumnCounter
1               abbc        2
2               def         1

改变一切的更新:

update tt
    set tt.SomeColumn = tt.SomeColumn + 'z'
from
    test_table as tt

现在我们有了:

MyPrimaryKey    SomeColumn  SomeColumnCounter
1               abbcz       3
2               defz        2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    相关资源
    最近更新 更多