【问题标题】:How can I edit values of an INSERT in a trigger on SQL Server?如何在 SQL Server 的触发器中编辑 INSERT 的值?
【发布时间】:2011-04-04 13:17:15
【问题描述】:

我有桌子Tb

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 的值,将其更改为大写,并在末尾添加了 edited

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

我该怎么做?

在插入更新后处理它会更好吗?还是用 INSTEAD OF INSERT 做一个触发器,每次表结构发生变化时修改它?

【问题讨论】:

  • 你不能用不同的方式来做这件事吗?我个人讨厌当我看到数据上发生奇怪的事情时,我终于意识到幽灵触发器正在做一些事情
  • 我将使用它来解决来自我无权访问的代码的问题。它插入一个项目的url,但它不会删除重音和特殊字符,我会为我做一个触发器。
  • 这不是一个很难的概念,令我惊讶的是,Microsoft 无法提供像 Oracle 那样简单的功能,您可以在插入之前通过编辑 :NEW 值来修改任何值。即,如果我想在插入用户名之前总是将它们转换为上(假设由于某种原因我不能只在代码中这样做),你可以有一个插入前触发器:NEW.username := UPPER(:NEW.username )。但是在 SQL Server 中,您不能对 INSERTED 临时表中的值执行等效操作,这真的很糟糕。
  • 是的,你可以。在instead of trigger 中,只需运行一个插入语句,将插入表中的所有列选择到真实表中,但修改您要设为upper 的列的select。例如,在代替插入触发器中,只需运行类似insert into Table (a,b,c) select a, ToUpper(b), c from inserted 的语句。微软技术将甲骨文从水中吹了出来。

标签: sql sql-server sql-server-2008 tsql triggers


【解决方案1】:

使用插入后触发器。从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 语句完成之前。因此,新的、不正确的值已经放置在目标表中。随着列的添加、删除等,此触发器不需要更改。

警告在触发后触发器之前强制执行完整性约束。因此,您不能设置检查约束来强制执行正确形式的 DESC。因为这会导致语句在触发器有机会修复任何东西之前失败。 (在依赖它之前请仔细检查这一段。我已经有一段时间没有写触发器了。)

【讨论】:

  • 此外,此解决方案不会使实际插入的值可用于OUTPUT 子句!
  • 在这种情况下什么是“Trgt”?
  • @CodenameCain 一个错误。应该是 Tb 或 from 子句需要是 from Tb Trgt。感谢您了解。
【解决方案2】:

我不确定您将在哪里获得 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

我已经在其中硬编码了“已编辑”这个词,因为我不确定您想从哪里获取值,但您可以轻松地将其替换为变量或另一个表中的值。

哦,也一定要把[]放在Desc周围,因为它是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 

【讨论】:

  • 我想获取插入的Desc的值并修改。我应该这么说的。我会更新我的问题,抱歉
  • 如果我的表发生变化怎么办?我每次都必须更新触发器?难道没有别的办法吗?
【解决方案3】:

临时表可以帮助使用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 

向表中添加新列时,无需修复此代码。

但要小心some additional overhead of temp tables

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

【讨论】:

  • 这会产生以下错误:只有在使用列列表并且 IDENTITY_INSERT 为 ON 时,才能为表“Tb”中的标识列指定显式值。
  • @Anders,我猜,这种方法可能与IDENTITY 列不兼容。但您也可以尝试将此列删除到触发器内的#tmp 表中。
【解决方案4】:

您可能想查看INSTEAD OF 触发器。

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

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

【讨论】:

  • 但要小心,因为 INSTEAD 假定您负责表中的所有列。
【解决方案5】:

不要使用 IDENTITY,而是使用 UNIQUEIDENTIFIER 和 NEWID():

CREATE TRIGGER MyTrigger ON MyTable INSTEAD OF INSERT AS BEGIN
; select * into #MyTriggertTempTable from inserted
; update #MyTriggertTempTable set ID=NEWID() where ID is null
; insert into MyTable select * from #MyTriggertTempTable
END

【讨论】:

  • OP 是关于在触发插入后更新列值。请详细说明您的答案,因为它看起来与提出的问题无关。
【解决方案6】:

您可以在 INSERT 之后使用触发器伪更新记录,但请注意您实际上是在更新记录,而不是替换 INSERT 之前的值。

CREATE TRIGGER [MISNT].[MyTriggerToReplaceColumnValueOnINSERT]
  ON [dbo].[myTableThatIsDoingTheINSERT]
  AFTER INSERT   --I prefer AFTER as it really is about after the fact!
AS
BEGIN
    UPDATE upd
    SET upd.ColA = 'some value'
    FROM [dbo].[myTableThatIsDoingTheINSERT] AS upd
        INNER JOIN inserted AS i ON i.ID = upd.ID
    WHERE upd.COLB IS NULL --optional WHERE if you want to only affect certain records
END
GO

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多