ORA-04091表格正在突变

问题描述

我有以下2个表: 运行:

options(tibble.print_min = 5)

和订单:

+--------+-------------+
| run_id | status      |
+========+=============+
| 1      | active      |
+--------+-------------+
| 2      | new         |
+--------+-------------+

请执行以下逻辑:当运行中的所有订单均具有相同状态时,应更新运行状态(与订单相同)

例如,当+----------+--------+--------------+ | order_id | run_id | order_status | +==========+========+==============+ | 1 | 1 | finished | +----------+--------+--------------+ | 2 | 1 | finished | +----------+--------+--------------+ | 3 | 1 | active | +----------+--------+--------------+ | 4 | 2 | new | +----------+--------+--------------+ | 5 | 2 | active | +----------+--------+--------------+ | 6 | 2 | active | +----------+--------+--------------+ 状态设置为order_id = 3时,'finished'状态也应设置为run_id=1。与'finished'相同,但状态为order_id = 4,然后'active'也设置为run_id = 2 should

负责检查订单状态并相应更新运行状态的过程:

'active'

我已经创建了触发器

CREATE OR REPLACE PROCEDURE  check_and_update_run_status  (in_order_id     IN   orders.order_id%TYPE,in_run_id       IN   runs.run_id%TYPE,in_order_status IN   orders.order_status%TYPE)
AS
   v_update_run VARCHAR2(1) := 'N';
BEGIN
   /*query the table ORDERS and check if all orders in the given in_run_id having the same status as in_order_status: */
  SELECT CASE
           WHEN NOT EXISTS ( SELECT *
                                 FROM ( SELECT order_id,order_status
                                          FROM orders
                                         WHERE run_id = in_run_id )
                                WHERE order_status <> in_order_status )
             THEN 'Y'
           END
    INTO v_update_run
    FROM dual;

    IF v_update_run THEN
      UPDATE runs
         SET run_status = in_order_status
       WHERE run_id = in_run_id;
    END IF;

END check_and_update_run_status;

逻辑失败,因为错误: CREATE OR REPLACE TRIGGER trigger1 AFTER INSERT OR UPDATE OF order_status ON orders FOR EACH ROW BEGIN check_and_update_run_status( in_order_id => :new.order_id,in_run_id => :new.run_id,in_po_status => :new.order_status ); END; 。 触发器正在调用一个过程,该过程查询被调用触发器的表。

解决这种问题的最佳方法是什么?

解决方法

还有其他方法可以解决mutating trigger,但我会尝试利用compound trigger的功能。话虽如此,我们应该尽量避免使用triggers,在您的情况下,在更新order status表中的orders列期间,请在其他程序单元或应用程序代码中的某个地方调用该过程。如我所见,这里每一行都没有依赖性,我们需要针对run_id而不是order_id更新。

已经说过,由于在此用例中我们不需要order_id参数,因此对过程进行了一些更改

CREATE OR REPLACE PROCEDURE check_and_update_run_status
(
   in_run_id       IN runs.run_id%TYPE,in_order_status IN orders.order_status%TYPE
) AS
   v_update_run VARCHAR2(1) := 'N';
BEGIN
   /*query the table ORDERS and check if all orders in the given in_run_id having the same status as in_order_status: */
   SELECT CASE
             WHEN NOT EXISTS (SELECT *
                   FROM   (SELECT order_id,order_status
                           FROM   orders
                           WHERE  run_id = in_run_id)
                   WHERE  order_status <> in_order_status) THEN
              'Y' ELSE 'N'
          END
   INTO   v_update_run
   FROM   dual;

   IF v_update_run = 'Y'
   THEN
      UPDATE runs 
         SET status = in_order_status 
       WHERE run_id = in_run_id;
   END IF;

END check_and_update_run_status;
/

并创建compound trigger并以如下方式调用该过程

CREATE OR REPLACE TRIGGER trigger1
   FOR INSERT OR UPDATE OF order_status ON orders
   COMPOUND TRIGGER

   --table type to store the status index by run_id value
   TYPE table_a_row_data_t IS TABLE OF orders.order_status%TYPE INDEX BY PLS_INTEGER;

   -- global variable for the compound trigger
   g_row_level_data table_a_row_data_t;

   AFTER EACH ROW IS
   BEGIN
      IF NOT g_row_level_data.exists(:new.run_id)
      THEN
         g_row_level_data(:new.run_id) := :new.order_status;
      END IF;
   END AFTER EACH ROW;

   AFTER STATEMENT IS
   BEGIN
      --loop through all run_id and update the status by calling the procedure
      --here I used collection.first..collection.last as the index is run_id itself  
      FOR runid IN g_row_level_data.first .. g_row_level_data.last
      LOOP
         check_and_update_run_status(in_run_id    => runid,in_order_status => g_row_level_data(runid));
      END LOOP;
   END AFTER STATEMENT;
END trigger1;
/

请进行测试,看看是否符合您的要求。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...