Ошибка мутации после триггера вставки - PullRequest
0 голосов
/ 13 мая 2018
CREATE OR REPLACE TRIGGER TRG_INVOICE
    AFTER INSERT
    ON INVOICE
    FOR EACH ROW
DECLARE
    V_SERVICE_COST FLOAT;
    V_SPARE_PART_COST FLOAT;
    V_TOTAL_COST FLOAT;
    V_INVOICE_DATE DATE;
    V_DUEDATE DATE;
    V_REQ_ID INVOICE.SERVICE_REQ_ID%TYPE;
    V_INV_ID INVOICE.INVOICE_ID%TYPE;
BEGIN
    V_REQ_ID := :NEW.SERVICE_REQ_ID;
    V_INV_ID := :NEW.INVOICE_ID;

    SELECT SUM(S.SERVICE_COST) INTO V_SERVICE_COST
    FROM INVOICE I, SERVICE_REQUEST SR, SERVICE S, SERVICE_REQUEST_TYPE SRT
    WHERE I.SERVICE_REQ_ID = SR.SERVICE_REQ_ID
    AND SR.SERVICE_REQ_ID = SRT.SERVICE_REQ_ID
    AND SRT.SERVICE_ID = S.SERVICE_ID
    AND I.SERVICE_REQ_ID = V_REQ_ID;


    SELECT SUM(SP.PRICE) INTO V_SPARE_PART_COST
    FROM INVOICE I, SERVICE_REQUEST SR, SERVICE S, SERVICE_REQUEST_TYPE SRT, 
    SPARE_PART_SERVICE SRP,
     SPARE_PART SP
    WHERE I.SERVICE_REQ_ID = SR.SERVICE_REQ_ID
    AND SR.SERVICE_REQ_ID = SRT.SERVICE_REQ_ID
    AND SRT.SERVICE_ID = S.SERVICE_ID
    AND S.SERVICE_ID = SRP.SERVICE_ID
    AND SRP.SPARE_PART_ID = SP.SPARE_PART_ID
    AND I.SERVICE_REQ_ID = V_REQ_ID;


    V_TOTAL_COST := V_SERVICE_COST + V_SPARE_PART_COST;


    SELECT SYSDATE INTO V_INVOICE_DATE FROM DUAL;


    SELECT ADD_MONTHS(SYSDATE, 1) INTO V_DUEDATE FROM DUAL;

    UPDATE INVOICE
    SET COST_SERVICE_REQ = V_SERVICE_COST, COST_SPARE_PART = 
    V_SPARE_PART_COST,
   TOTAL_BALANCE = V_TOTAL_COST, PAYMENT_DUEDATE = V_DUEDATE, INVOICE_DATE = 
    V_INVOICE_DATE
    WHERE INVOICE_ID = V_INV_ID;



END;

Я пытаюсь вычислить некоторые столбцы после того, как пользователь вставит строку. Используя service_request_id, я хочу рассчитать услугу / части / общую стоимость. Кроме того, я хотел бы сгенерировать создание и сроки. Но я продолжаю получать

Счет-фактура мутирует, триггер / функция может его не видеть

Не уверен, как таблица мутирует после оператора вставки.

1 Ответ

0 голосов
/ 13 мая 2018

Не уверен, как таблица изменяется после оператора вставки.

Представьте себе простую таблицу:

create table x(
  x int,
  my_sum int
);

и триггер AFTER INSERT FOR EACH ROW,аналогично вашему, который вычисляет сумму всех значений в таблице и обновляет столбец my_sum.

Теперь представьте себе этот оператор вставки:

insert into x( x )
select 1 as x from dual
connect by level <= 1000;

Этот единственный оператор в основном вставляет 1000 записей, каждая со значением 1, см. Эту демонстрацию: http://sqlfiddle.com/#!4/0f211/7


Поскольку в SQL каждый отдельный оператор должен быть ATOMIC (подробнее об этом здесь: Согласованность чтения на уровне оператора , Oracle может выполнить этот запрос любым способом, пока конечный результат верен (непротиворечиво)Он может сохранять записи в порядке выполнения, может быть в обратном порядке, он может разделять пакет на 10 потоков и делать это параллельно.


Поскольку триггер срабатывает индивидуально после вставки каждой строки, и он не может знать заранее «конечный» результат, тогда, учитывая вышеизложенное, возможны все нижеприведенные результаты в зависимости от «внутреннего» метода, выбранного Oracle для выполнения этого запроса. Как видите, эти результаты не соответствуют определению согласованностиИ Oracle предотвращает эту ошибку выдачи мутирующей таблицы.

Другими словами - ваши предположения неверны, а вашиesign имеет недостатки, вам нужно изменить его.

| X | MY_SUM |
|---|--------|
| 1 |      1 |
| 1 |      2 |
| 1 |      3 |
| 1 |      4 |
...
...

или, может быть:

| X | MY_SUM |
|---|--------|
| 1 |   1000 |
| 1 |   1000 |
| 1 |   1000 |
| 1 |   1000 |
| 1 |   1000 |
| 1 |   1000 |
| 1 |   1000 |
...

или, может быть:

| X | MY_SUM |
|---|--------|
| 1 |      4 |
| 1 |      8 |
| 1 |     12 |
| 1 |     16 |
| 1 |     20 |
| 1 |     24 |
| 1 |     28 |
...
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...