столбец здесь не разрешен

#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. применимы только к таблице, в которой установлен триггер.