DML 触发器的多行注意事项

为 DML 触发器编写代码时,请考虑导致触发器激发的语句可能是影响多行数据(而不是单行)的单个语句。这对于 UPDATE 和 DELETE 触发器很常见,因为这些语句经常影响多行。而这对于 INSERT 触发器比较少见,因为基本 INSERT 语句仅添加单行。但是,由于 INSERT 触发器可以通过 INSERT INTO (table_name) SELECT 语句激发,所以插入许多行可能导致调用单个触发器。

在下列情况下关于多行的注意事项尤为重要:DML 触发器的功能自动重新计算一个表中的汇总值,并将结果存储在另一个表中以继续进行计数。

注意:
我们建议不要在触发器中使用游标,因为它们可能会降低性能。若要设计一个影响多行的触发器,请使用基于行集的逻辑,而不要使用游标。
 

  示例
下列示例中的 DML 触发器用于在 AdventureWorks 示例数据库的另一个表中存储某列的运行总计。

A. 存储单行插入的运行总计
第一种 DML 触发器在一行数据加载到 PurchaseOrderDetail 表中时适合于单行插入。INSERT 语句激发 DML 触发器,新行在触发器执行期间加载到插入的表中。UPDATE 语句读取该行的 LineTotal 列值,并将该值与 PurchaseOrderHeader 表的 SubTotal 列中的现有值相加。WHERE 子句确保 PurchaseOrderDetail 表中的更新行与插入的表中 PurchaseOrderID 行相匹配。

复制代码 -- Trigger is valid for single-row inserts.
USE AdventureWorks;
GO
CREATE TRIGGER NewPODetail
ON Purchasing.PurchaseOrderDetail
AFTER INSERT AS
   UPDATE PurchaseOrderHeader
   SET SubTotal = SubTotal + LineTotal
   FROM inserted
   WHERE PurchaseOrderHeader.PurchaseOrderID = inserted.PurchaseOrderID ;
B. 存储多行或单行插入的运行总计
对于多行插入,示例 A 中的 DML 触发器可能不会正确运行;位于 UPDATE 语句 (SubTotal + LineTotal) 中赋值表达式右侧的表达式只能是一个值,而不能是一个值列表。因此,该触发器的作用是检索插入的表中任意一行的值,并将该值与 PurchaseOrderHeader 表中的现有 SubTotal 值相加,以获得特定 PurchaseOrderID 值。如果某个 PurchaseOrderID 值在插入的表中出现多次,则此操作可能无法达到预期效果。

若要正确更新 PurchaseOrderHeader 表,必须允许对插入的表中的多行使用触发器。可以通过使用 SUM 函数达到此目的,该函数计算每个 PurchaseOrderID 的插入的表中许多行的总 LineTotal。SUM 函数包含在相关子查询(括号中的 SELECT 语句)中。此子查询将为插入的表中的每个 PurchaseOrderID 返回一个值,该值与 PurchaseOrderHeader 表中的 PurchaseOrderID 匹配或相关。

复制代码 -- Trigger is valid for multirow and single-row inserts.
USE AdventureWorks;
GO
CREATE TRIGGER NewPODetail2
ON Purchasing.PurchaseOrderDetail
AFTER INSERT AS
   UPDATE PurchaseOrderHeader
   SET SubTotal = SubTotal +
      (SELECT SUM(LineTotal)
      FROM inserted
      WHERE PurchaseOrderHeader.PurchaseOrderID
       = inserted.PurchaseOrderID)
   WHERE PurchaseOrderHeader.PurchaseOrderID IN
      (SELECT PurchaseOrderID FROM inserted);
此触发器还适合于单行插入;LineTotal 值列的和为单行的和。但是,对于此触发器,相关子查询和 WHERE 子句中使用的 IN 运算符需要从 SQL Server 2005 中进行其他处理。这对于单行插入来说,是不必要的。

C. 基于插入类型存储运行总计
可以更改触发器以针对不同行数使用最优方法。例如,可以在触发器逻辑中使用 @@ROWCOUNT 函数来区分单行插入和多行插入。

复制代码 -- Trigger valid for multirow and single row inserts
-- and optimal for single row inserts.
USE AdventureWorks;
GO
CREATE TRIGGER NewPODetail3
ON Purchasing.PurchaseOrderDetail
FOR INSERT AS
IF @@ROWCOUNT = 1
BEGIN
   UPDATE PurchaseOrderHeader
   SET SubTotal = SubTotal + LineTotal
   FROM inserted
   WHERE PurchaseOrderHeader.PurchaseOrderID = inserted.PurchaseOrderID

END
ELSE
BEGIN
      UPDATE PurchaseOrderHeader
   SET SubTotal = SubTotal +
      (SELECT SUM(LineTotal)
      FROM inserted
      WHERE PurchaseOrderHeader.PurchaseOrderID
       = inserted.PurchaseOrderID)
   WHERE PurchaseOrderHeader.PurchaseOrderID IN
      (SELECT PurchaseOrderID FROM inserted)
END;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值