2010-08-26 246 views
22

我有表Tb如何在SQL Server的触发器上编辑INSERT的值?

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 

我要创建INSERT触发器,这将改变插入Desc的值,例如:

INSERT INTO Tb(Name, Desc) VALUES ('x', 'y') 

会导致

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 
2 | x  | Y edited 

在上面的例子中,我得到了插入的值Desc将它改为大写和a末了edited

这就是我所需要的,获取正在插入并修改它的Desc

我该怎么做?

插入更新后处理它会更好吗?或者使用INSTEAD OF INSERT触发并在每次表结构更改时对其进行修改?

+1

难道你不能以不同的方式做到这一点?我个人讨厌当我看到数据发生奇怪的事情时,我终于意识到,鬼触发器正在做一些事情 – 2010-08-26 22:45:49

+0

我将用它来解决来自我无法访问的代码的问题。它插入一个项目的URL,但它不会删除重音和特殊字符,我会为我做一个触发器。 – BrunoLM 2010-08-26 23:08:31

+1

这不是一个这么难的概念,它让我难以置信,微软无法提供像Oracle这样的简单功能,您可以在插入之前通过编辑:NEW值来修改任何值。也就是说,如果我想在插入它们之前总是将用户名改为upper(假设我不能在代码中出于某种原因执行此操作),则可以使用以下插入触发器:NEW.username:= UPPER(:NEW.username )。但是,在SQL Server中,您无法在INSERTED临时表中执行相同的操作,而这真的很糟糕。 – Jim 2012-05-15 18:43:56

回答

30

使用插入后触发器。在主键上从inserted伪表加入Tb。然后更新desc的值。喜欢的东西:(但可能无法编译)

CREATE TRIGGER TbFixTb_Trg 
ON Tb 
AFTER INSERT 
AS 
BEGIN 
    UPDATE Tb 
    SET DESC = SomeTransformationOf(i.DESC) 
    FROM Tb 
    INNER JOIN inserted i on i.Id = Tb.Id 
END 
GO 

这触发发生中的插入之后发生,但insert语句完成之前。所以新的,不正确的值已经放置在目标表中。这个触发器不需要随着列的添加,删除等而改变。

警告完整性约束在after触发器触发前执行。所以你不能放置一个检查约束来强制适当的DESC形式。因为这会在触发器有机会修复任何事情之前导致语句失败。 (请仔细依靠前检查这一段它已经一段时间,因为我写了一个触发器。)

+0

此外,此解决方案不会将实际插入的值用于“OUTPUT”子句! – 2015-08-26 10:27:23

+0

在这种情况下,“Trgt”是什么? – CodenameCain 2016-04-11 20:14:39

+1

@CodenameCain一个错误。应该是'Tb'或from子句需要'来自Tb Trgt'。感谢捕捉。 – 2016-04-11 20:47:25

3

你可能想看看INSTEAD OF触发器。

CREATE TRIGGER Tb_InsteadTrigger on Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
... 

这将允许您在数据进入表格之前操作数据。触发器负责将数据插入表中。

24

我不知道你将在哪里获得desc的实际新值,但我假设你从另一个表或其他表中获得它。但是你可能有这样想要这样做的理由,所以下面是我将如何去做的一个例子。

你想要什么叫做INSTEAD OF INSERT触发器,它会触发而不是使用每个逻辑给它的插入。

CREATE TRIGGER trgUpdateDesc 
ON Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    INSERT INTO Tb (Name, [Desc]) 
    SELECT Name, [Desc] + 'edited' 
    FROM inserted 
END 
GO 

我硬编码的字“编辑”在那里,我不知道,你想要得到的值,但是你可以很容易地替换成一个变量或从另一个表中的值。

哦,也可以确保把[]周围的说明,因为它是在SQL Server中的关键字(代表降序)

希望帮助!

编辑:

如果你想多一点健壮,以便它不依赖于表结构为多,你可以使用一个AFTER INSERT触发器只更新场像这样。

CREATE TRIGGER [dbo].[trgUpdateDesc] 
    ON [dbo].[Tb] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    UPDATE Tb 
    SET [Desc] = UPPER(inserted.[Desc]) + ' Edited' 
    FROM inserted INNER JOIN Tb On inserted.id = Tb.id 
END 
+0

我想获取插入的“Desc”的值并对其进行修改。我应该这样说。我会更新我的问题,对不起 – BrunoLM 2010-08-26 23:05:09

+0

如果我的表格发生变化,该怎么办?我将不得不每次更新触发器?没有其他方法可以做到这一点吗? – BrunoLM 2010-08-26 23:28:29

8

临时表可以帮助使用INSTEAD OF INSERT触发,同时避免明确列出所有不相关的表列:

CREATE TRIGGER trgUpdateDesc 
    ON Tb 
    INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    select * into #tmp from inserted; 
    UPDATE #tmp SET Desc = Desc + 'edited' --where ...; 
    insert into Tb select * from #tmp; 
    drop table #tmp; 
END 

当新列添加到表中时,不需要修复此代码。请注意0​​。

另请注意,对于批量DML操作,SQL Server会触发一次,并且必须触发correctly handle multi-row inserts

+0

这会产生以下错误:仅当使用列列表且IDENTITY_INSERT为ON时,才可以指定表'Tb'中标识列的显式值。 – 2017-03-29 14:51:12

+1

@Anders,我想这种方法可能与[IDENTITY](http://stackoverflow.com/questions/16766963/insert-record-to-sql-table-with-identity-column)列不兼容。但是你也可以尝试在触发器的'#tmp'表中删除这一列。 – Vadzim 2017-03-30 09:13:51