#sql #oracle #function #plsql #triggers
#sql #Oracle #функция #plsql #запускает
Вопрос:
CREATE OR REPLACE TRIGGER update_QOH
BEFORE INSERT ON ORDERLINE
FOR EACH ROW
DECLARE
QOH_PRODUCT PRODUCT.QOH%TYPE;
ORD_NO ORDERS.ORDER_NO%TYPE;
BEGIN
SELECT QOH INTO QOH_PRODUCT FROM PRODUCT
WHERE :old.product_no = :new.product_no;
SELECT ORDER_NO INTO ORD_NO FROM ORDERLINE
WHERE :old.order_no = :new.order_no;
IF (:new.QTY <= QOH_PRODUCT) THEN
UPDATE PRODUCT SET QOH = QOH_PRODUCT - :new.QTY;
ELSE
send_email(ord_no, 'Backorder');
INSERT INTO BACKORDER
VALUES (backorder_no_seq.NEXTVAL, :new.product_no, :new.qty, SYSDATE);
INSERT INTO PRODVENDOR
VALUES (po_no_seq.NEXTVAL, vendor_no, :new.product_no, vend_qty,
shipping_method, SYSDATE, NULL, NULL, NULL);
END IF;
END;
/
-------------------------------------------------------------------------------
Error(13,3): PL/SQL: SQL Statement ignored
Error(13,91): PL/SQL: ORA-00984: column not allowed here
--------------------------------------------------------------------------------
Таблица продуктов (P_no, QOH и т.д.)
Таблица строк заказа (OL_no, кол-во и т.д.)
Таблица обратного порядка (B_no, B_QTY и т.д.)
Таблица поставщиков (V_no и т.д.)
Мне нужно убедиться, что, когда клиент покупает продукт, в таблице product достаточно QOH, если есть, QOH в продукте следует уменьшить (обновить). Если нет, отправьте электронное письмо клиенту, обновите таблицу обратных заказов, и продукт следует заказать у поставщика.
Ответ №1:
Измените эту строку:
QOH = :old.QOH - :new.QTY
Для
QOH := :old.QOH - :new.QTY
В PL / SQL :=
есть оператор присваивания, поэтому используйте его при настройке переменной PL / SQL.
Каким бы ни был источник ваших ошибок компиляции, отправка электронной почты из триггера кажется плохой идеей.
Комментарии:
1. Спасибо, я попытался изменить оператор присваивания, но я все еще получаю так много ошибок.
Ответ №2:
Во-первых, рассмотрите возможность вставки в процедуру вместо триггера. (И, возможно, более полезное имя). Вставка в другие таблицы или обновление отсюда других таблиц может привести к путанице, если позже они получат свои собственные триггеры, и будет трудно отслеживать, что происходит, где и когда.
Во-вторых, похоже, что это не очень хорошо справится с одновременными вставками — две новые вставки строки заказа для одного и того же продукта одновременно попытаются обновить QOH продукта с, вероятно, неожиданными или нежелательными результатами — QOH может стать отрицательным, например. Вы также потенциально можете получить несколько заказов поставщику; каждая строка заказа, в которой запрашивается отсутствующий на складе продукт, будет отправлять поставщику новый заказ, даже если количество в каждой строке заказа равно 1, а вы заказываете у поставщика 100 штук одновременно.
В-третьих, различные ошибки кода; я начну с пары более очевидных:
a) Вы выбираете из PRODUCT
и ORDERLINE
с WHERE :old.product_no = :new.product_no
помощью. Я не уверен, :OLD
что он вообще установлен в триггере before-insert , но если это так, то он будет таким же, как :NEW
или null , так что вы, возможно, получите ошибки ORA-02112 или ORA-01403, поскольку он найдет все строки или, возможно, ни одной.
b) Ваш select from ORDERLINE
в любом случае не вернет строк в первой строке заказа и несколько строк начиная с третьей, поэтому вы снова получите ошибки ORA-01403 и ORA-02112. Но это бессмысленно, поскольку вы просто выбираете значение, к которому делаете запрос. Вы можете просто использовать :NEW
значение в вызове электронной почты.
c) Ваше обновление PRODUCT
не имеет WHERE
предложения, поэтому все значения QOH будут обновлены.
CREATE OR REPLACE TRIGGER update_QOH
BEFORE INSERT ON ORDERLINE
FOR EACH ROW
DECLARE
QOH_PRODUCT PRODUCT.QOH%TYPE;
BEGIN
SELECT QOH INTO QOH_PRODUCT FROM PRODUCT
WHERE product_no = :new.product_no;
IF (:new.QTY <= QOH_PRODUCT) THEN
UPDATE PRODUCT SET QOH = QOH_PRODUCT - :new.QTY;
WHERE product_no = :new.product_no;
ELSE
send_email(:new.order_no, 'Backorder');
INSERT INTO BACKORDER
VALUES (backorder_no_seq.NEXTVAL, :new.product_no, :new.qty, SYSDATE);
INSERT INTO PRODVENDOR
VALUES (po_no_seq.NEXTVAL, vendor_no, :new.product_no, vend_qty,
shipping_method, SYSDATE, NULL, NULL, NULL);
END IF;
END;
/
d) Откуда vend_no
, vend_qty
и shipping_method
берутся при вставке в PRODVENDOR
? Это единственная очевидная ошибка компиляции, которая выскакивает.
e) Вы не указываете столбцы таблицы во вставках. Это вызовет ошибку компиляции, если у вас значения в неправильном порядке или какие-либо отсутствуют, но вы не можете определить это, просто взглянув на код. (Вы не сказали, какие ошибки ‘so may’ возникают после изменения @WW, поэтому не знаю, имеет ли это значение). И если позже будет добавлен другой столбец, этот триггер станет недействительным, поэтому обычно рекомендуется явно перечислять столбцы.
Функционально вы, похоже, отправляете электронное письмо, в котором говорится, что весь заказ находится в резервном заказе, а не только этот продукт; и, похоже, нет никаких связей между текущим заказом и тем, что вы вводите в BACKORDER
и PRODVENDOR
.
Комментарии:
1. Возможно, это прозвучало несколько более жестко, чем предполагалось. Возможно, я был в худшем настроении, чем предполагал этим утром…
Ответ №3:
Вы уверены, что QOH — это поле в таблице ORDERLINE? Ключевые слова :OLD. и :NEW. применимы только к таблице, в которой установлен триггер.