我的 PLSQL 触发器没有循环遍历表

Posted

技术标签:

【中文标题】我的 PLSQL 触发器没有循环遍历表【英文标题】:My PLSQL trigger is not looping through the table 【发布时间】:2019-04-30 16:16:33 【问题描述】:

我有一个小组项目,我们正在使用 PLSQL 来制作购物车应用程序。我们正在创建一个触发器以取消购物车并将所有商品退回库存。就像现在一样,如果您将多个商品添加到购物车,当触发器运行时,它只会添加一个产品的库存,而不是全部,因此由于某种原因,触发器不会循环。我们的项目明天到期,所以请帮忙!

create or replace TRIGGER Cancel
Before delete on sc_cart
For each row

DECLARE
ws_prod_id number(3,0);
ws_item_quantity_in_cart number(7,0);

BEGIN

/*product and quantity in cart*/
select max(item_product_id), max(item_quantity_in_cart) into ws_prod_id, ws_item_quantity_in_cart
from sc_items
where item_cart_id = :old.cart_id;

update sc_product set prod_quan_avail = prod_quan_avail + ws_item_quantity_in_cart where ws_prod_id = prod_id;
update sc_product set prod_quan_sold = prod_quan_sold - ws_item_quantity_in_cart where ws_prod_id = prod_id;

delete from sc_items
where :old.cart_id = item_cart_id;

END;

我们需要代码遍历表格的每一行并将购物车中的每件商品退回库存。

【问题讨论】:

为什么会有“循环”?触发器不循环,并且您没有编写任何循环。你得到一个 product_id 然后你就停下来了。 【参考方案1】:

我敦促您不要将所有这些代码都放在触发器中,而是像这样创建一个 cancel_order 过程:

CREATE OR REPLACE PROCEDURE cancel_card (cart_id_in IN INTEGER)
IS
   ws_prod_id                 NUMBER (3, 0);
   ws_item_quantity_in_cart   NUMBER (7, 0);
BEGIN
   /*product and quantity in cart*/
   SELECT MAX (item_product_id), MAX (item_quantity_in_cart)
     INTO ws_prod_id, ws_item_quantity_in_cart
     FROM sc_items i
    WHERE i.item_cart_id = cancel_card.cart_id_in;

   UPDATE sc_product p
      SET prod_quan_avail = prod_quan_avail + ws_item_quantity_in_cart,
          prod_quan_sold = prod_quan_sold - ws_item_quantity_in_cart
    WHERE p.prod_id = cancel_card.ws_prod_id;

   DELETE FROM sc_items o
         WHERE i.cart_id = cancel_card.cart_id_in;

   DELETE FROM sc_cart c
         WHERE c.cart_id = cancel_card.cart_id_in;
END;

然后您可以根据需要调用此过程,但不是从触发器内部调用。

您应该避免在触发器中使用 SQL 语句。副作用和变异表错误的可能性太大。

【讨论】:

【参考方案2】:

当你这样做时:

   SELECT MAX (item_product_id), MAX (item_quantity_in_cart)
     INTO ws_prod_id, ws_item_quantity_in_cart
     FROM sc_items i
    WHERE i.item_cart_id = cancel_card.cart_id_in;

您只是选择一 (1) 个产品 => max(item_product_id)

所以,这是唯一更新的产品,更糟糕的是,它最终会从另一个产品更新为 max(qty)...

您需要一个购物车产品的光标,并为每个产品进行必要的更新。

触发器没有好坏之分,但作为一个基本规则,我完全同意 Steven Feuerstein 的评论,你应该避免它们。但有时你不能。

也许更好的设计是混合设计: - 构建一个基于购物车 id 清除购物车的存储过程 - 从触发器(如果你真的必须)或从外部(购物车管理过程)调用该过程作为更好的选择。

【讨论】:

以上是关于我的 PLSQL 触发器没有循环遍历表的主要内容,如果未能解决你的问题,请参考以下文章

向我的 H2 数据库中的每个表添加触发器

如果 Column_X 更新,PLSQL 触发器记录对审计表的更新

oracle(sql)基础篇系列——PLSQL游标存储过程触发器

PLSQL 触发器在插入后更新记录

Oracle-4 - :超级适合初学者的入门级笔记:plsql,基本语法,记录类型,循环,游标,异常处理,存储过程,存储函数,触发器

循环遍历多个表的 plsql 代码