таблица мутирует, триггер / функция может ее не видеть; нужен после / запрос уровня строки - PullRequest
0 голосов
/ 07 мая 2019

Как переписать триггер, чтобы избежать ошибки "BB_BASKET мутирует, триггер / функция может его не видеть"

Домашние инструкции: создайте триггер с именем BB_SALESUM_TRG, который обновляет BB_SALES_SUM соответственно, когда заказ подтвержден или столбец ORDERPLACED в таблице BB_BASKET обновлен до 1.

Я искал решения для этой проблемы, не меняя домашнего задания, которое указывает, что запрос должен быть ПОСЛЕ триггера, так как инвентарь должен быть обновлен после подтверждения заказа. Другие предложения SO состоят в том, чтобы изменить AFTER на BEFORE или INSERT, но триггер BEFORE будет некорректно обновлять инвентарь перед подтверждением, и INSERT не может использоваться с триггером уровня строки. Другие предложения вообще избегать триггеров хороши для реального мира, но не для домашней работы, особенно для триггеров.

Триггер уровня оператора может избежать проблемы, но я не могу использовать свое предложение WHEN с триггером уровня оператора, и я думаю, что мне нужно WHEN, или мой код обновит таблицу независимо от количества.

Добавление прагмы автономной транзакции, похоже, не избавляет от ошибки

Другой подобный код в моей домашней книге использует AFTER с оператором SELECT в курсоре без проблем, поэтому я не думаю, что оператор SELECT в курсоре вызывает у меня горе.

CREATE TABLE BB_SALES_SUM (
product_id VARCHAR2(30) PRIMARY KEY,
total_sales NUMBER(8,2),
total_qty NUMBER(10),
OrderPlaced number(1)
);

Set ServerOutput On;
CREATE OR REPLACE TRIGGER bb_salessum_trg
AFTER UPDATE OF orderplaced ON bb_basket
FOR EACH ROW
WHEN(OLD.orderplaced <> 1 AND NEW.orderplaced = 1)
DECLARE
CURSOR basketitem_cur IS
   SELECT idbasket, total, quantity, orderplaced
   FROM bb_basket
   WHERE idbasket=:NEW.idbasket;
BEGIN
   FOR basketitem_rec in basketitem_cur LOOP
    UPDATE bb_sales_sum
    SET total_qty = basketitem_rec.quantity
    WHERE product_id = basketitem_rec.idbasket;
END LOOP;
END;
/

UPDATE bb_basket SET orderplaced = 1 WHERE idbasket = 14

1 Ответ

2 голосов
/ 07 мая 2019

Вам нужно подумать о логике проблемы.bb_sales_sum.total_qty - это сумма, то есть сумма всех проданных товаров.Ваш триггер не рассчитывает итоговую сумму, поэтому (если он выполнен) результат будет неверным: bb_sales_sum.total_qty будет установлено значение товара в последней корзине, а не сумма проданного товара.

Внимательно прочитав вопрос, мы увидим, что он дает толчок в правильном направлении:

обновляет BB_SALES_SUM соответственно, когда заказ подтвержден или столбец ORDERPLACED в таблице BB_BASKET обновлен до 1.

Триггер должен только обновлять сумму, а не перезаписывать ее.Давайте попробуем это.

Примечание: это выглядит неправильно - product_id = :new.idbasket - но вы не опубликовали полный набор таблиц или пример данных.Также вы не указали, как «заказ подтвержден» .Итак, я собираюсь предположить, что ваша логика фильтрации верна.Возможно, вам придется настроить его.

CREATE OR REPLACE TRIGGER bb_salessum_trg
AFTER UPDATE OF orderplaced ON bb_basket
FOR EACH ROW
WHEN(OLD.orderplaced <> 1 AND NEW.orderplaced = 1)
BEGIN

    UPDATE bb_sales_sum
    SET total_qty = total_qty + :new.quantity
    WHERE product_id = :new.idbasket;

END;
/
...