Возникла проблема с триггером, который срабатывает после обновления / вставки / удаления строки в таблице - PullRequest
0 голосов
/ 06 мая 2019

У меня есть небольшая система, которую я должен был создать для назначения.Он предназначен для облегчения просмотра соответствующих данных в базе данных для «управления».

У меня есть три таблицы:

  • CLIENT просто содержит идентификатор клиента, имя клиента, номер телефона и адрес электронной почты.

  • PROJECT так же просто.Он имеет идентификатор проекта, идентификатор клиента, который ссылается на CLIENT, и имя проекта.

  • PROJECT_PAYMENT содержит идентификатор платежа по проекту, идентификатор проекта, который ссылается на PROJECT, а затем множество строк с датой платежа, выплаченной суммой, просроченной суммой и т. Д. И т. Д.

Затем у меня четыре просмотра:

  • PAYMENTS_COMPLETED, который показывает, как вы уже догадались, выполненные платежи.

  • PAYMENTS_OUTSTANDING, что противоположно приведенному выше.

  • PAYMENTS_DISPUTED, который показывает любые платежи, которые были оспорены либо клиентом, либо компанией.

  • PAYMENTS_PAST_DUE, который показывает платежи, которые не были завершены, и дату истечения срока платежа.

У меня есть процедуракоторый обновляет все эти четыре представления:

create or replace PROCEDURE UPDATE_VIEWS AUTHID CURRENT_USER
IS

PAYMENTS_COMPLETED_STMNT VARCHAR2(5000);
PAYMENTS_DISPUTED_STMNT VARCHAR2(5000);
PAYMENTS_OUTSTANDING_STMNT VARCHAR2(5000);
PAYMENTS_PAST_DUE_STMNT VARCHAR2(5000);

BEGIN

    PAYMENTS_COMPLETED_STMNT := 'CREATE OR REPLACE VIEW PAYMENTS_COMPLETED AS SELECT PP.PROJECT_PAYMENT_ID, P.PROJECT_NAME, C.CLIENT_ID, C.CLIENT_NAME, PP.PAYMENT_DUE, PP.PAYMENT_TOTAL FROM PROJECT_PAYMENT PP JOIN PROJECT P ON PP.PROJECT_ID = P.PROJECT_ID JOIN CLIENT C ON C.CLIENT_ID = P.CLIENT_ID WHERE PP.PAYMENT_PAID >= PP.PAYMENT_TOTAL';
    PAYMENTS_DISPUTED_STMNT := 'CREATE OR REPLACE VIEW PAYMENTS_DISPUTED AS SELECT PP.PROJECT_PAYMENT_ID, P.PROJECT_NAME, C.CLIENT_ID, C.CLIENT_NAME, PP.PAYMENT_DUE, PP.PAYMENT_TOTAL, PP.PAYMENT_PAID, PP.PAYMENT_TOTAL-PP.PAYMENT_PAID AS "PAYMENT_REMAINING", PP.PAYMENT_DISPUTED_CLIENT, PP.PAYMENT_DISPUTED_COMPANY FROM PROJECT_PAYMENT PP JOIN PROJECT P ON PP.PROJECT_ID = P.PROJECT_ID JOIN CLIENT C ON C.CLIENT_ID = P.CLIENT_ID WHERE UPPER(PP.PAYMENT_DISPUTED_CLIENT) = ''Y'' OR UPPER(PP.PAYMENT_DISPUTED_COMPANY) = ''Y''';
    PAYMENTS_OUTSTANDING_STMNT := 'CREATE OR REPLACE VIEW PAYMENTS_OUTSTANDING AS SELECT PP.PROJECT_PAYMENT_ID, P.PROJECT_NAME, C.CLIENT_ID, C.CLIENT_NAME, PP.PAYMENT_DUE, PP.PAYMENT_TOTAL, PP.PAYMENT_PAID, PP.PAYMENT_TOTAL - PP.PAYMENT_PAID AS "PAYMENT_REMAINING" FROM PROJECT_PAYMENT PP JOIN PROJECT P ON PP.PROJECT_ID = P.PROJECT_ID JOIN CLIENT C ON C.CLIENT_ID = P.CLIENT_ID WHERE PP.PAYMENT_PAID < PP.PAYMENT_TOTAL';
    PAYMENTS_PAST_DUE_STMNT := 'CREATE OR REPLACE VIEW PAYMENTS_PAST_DUE AS SELECT PP.PROJECT_PAYMENT_ID, P.PROJECT_NAME, C.CLIENT_ID, C.CLIENT_NAME, PP.PAYMENT_DUE, PP.PAYMENT_TOTAL, PP.PAYMENT_PAID, PP.PAYMENT_TOTAL-PP.PAYMENT_PAID AS "PAYMENT_REMAINING" FROM PROJECT_PAYMENT PP JOIN PROJECT P ON PP.PROJECT_ID = P.PROJECT_ID JOIN CLIENT C ON C.CLIENT_ID = P.CLIENT_ID WHERE PP.PAYMENT_DUE < TRUNC(SYSDATE) AND PP.PAYMENT_PAID < PP.PAYMENT_TOTAL';

    EXECUTE IMMEDIATE PAYMENTS_COMPLETED_STMNT;
    DBMS_OUTPUT.PUT_LINE('UPDATED PAYMENTS_COMPLETED VIEW.');
    EXECUTE IMMEDIATE PAYMENTS_DISPUTED_STMNT;
    DBMS_OUTPUT.PUT_LINE('UPDATED PAYMENTS_DISPUTED VIEW.');
    EXECUTE IMMEDIATE PAYMENTS_OUTSTANDING_STMNT;
    DBMS_OUTPUT.PUT_LINE('UPDATED PAYMENTS_OUTSTANDING VIEW.');
    EXECUTE IMMEDIATE PAYMENTS_PAST_DUE_STMNT;
    DBMS_OUTPUT.PUT_LINE('UPDATED PAYMENTS_PAST_DUE VIEW.');

END;

Теперь перейдем к моей проблеме.Я создал следующий триггер:

create or replace TRIGGER UPDATE_VIEWS_ON_PP_INSERT_TG
AFTER INSERT OR UPDATE OR DELETE ON PROJECT_PAYMENT
BEGIN
    UPDATE_VIEWS();
    DBMS_OUTPUT.PUT_LINE('ALL VIEWS HAVE BEEN UPDATED.');
END;

Я хотел, чтобы он срабатывал всякий раз, когда кто-то вставлял новую строку, обновлял строку или удалял строку из PROJECT_PAYMENT.Триггер запускает , однако выдает следующую ошибку и останавливает запись, которую я только что пытался вставить:

One error saving changes to table "O015596H"."PROJECT_PAYMENT":
Row 11: ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "O015596H.UPDATE_VIEWS", line 16
ORA-06512: at "O015596H.UPDATE_VIEWS_ON_PP_INSERT_TG", line 2
ORA-04088: error during execution of trigger 'O015596H.UPDATE_VIEWS_ON_PP_INSERT_TG'
ORA-06512: at line 1

Local changes cleared

Понятия не имею, что означает эта ошибка иликак это исправить, так что помог кто-то здесь мог сказать мне, в чем проблема.Я знаю, это говорит, что он не может совершить в триггере, но я не знаю, как я должен избавиться от ошибки.

РЕДАКТИРОВАТЬ 1:

Я погуглил и увидел, что добавление:

FOR EACH ROW
DECLARE
    PRAGMA AUTONOMOUS_TRANSATION;

... выше строки «НАЧАЛО» будет работать, но теперь я получаю ошибку «Недостаточные привилегии»:

One error saving changes to table "O015596H"."PROJECT_PAYMENT":
Row 11: ORA-01031: insufficient privileges
ORA-06512: at "O015596H.UPDATE_VIEWS", line 16
ORA-06512: at "O015596H.UPDATE_VIEWS_ON_PP_INSERT_TG", line 4
ORA-04088: error during execution of trigger 'O015596H.UPDATE_VIEWS_ON_PP_INSERT_TG'
ORA-06512: at line 1

1 Ответ

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

Представления являются постоянными структурами базы данных.Просто напишите сценарии DDL, как для таблиц или чего-либо еще.Запустите их один раз и дайте привилегии на просмотр людям, которым нужен доступ.Работа хорошая.

Помимо всего прочего, вы не хотите заново создавать эти объекты каждый раз, когда кто-то записывает платеж по проекту.Получение объектных блокировок было бы трудной задачей, и пользователи находили бы, что их попытки запрашивать эти представления постоянно терпят неудачу из-за недействительности состояния сеанса.

Чтобы объяснить полученные ошибки:

ORA-04092: невозможно выполнить COMMIT в триггере

DDL в Oracle - например, операторы CREATE VIEW - выдавать неявные фиксации.Oracle не позволяет нам включать COMMIT (или ROLLBACK) в триггер, потому что триггеры запускаются как часть транзакции, но транзакция не обязательно завершается при срабатывании триггера.

ORA-01031: недостаточно привилегий

Похоже, у вас есть привилегия CREATE VIEW, предоставленная через роль.Мы не можем использовать роли, предоставленные косвенно через роли в программных единицах (хранимые процедуры, представления или триггеры).


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

Использование триггера для создания представления не демонстрирует, что вы знаете «как использовать процедуры, функции и триггеры» .На самом деле, скорее наоборот.

Более простым и лучшим вариантом использования триггера будет использование amount paid для поддержки amount outstanding для PROJECT_PAYMENT.

create or replace TRIGGER UPDATE_VIEWS_ON_PP_INSERT_TG
before update ON PROJECT_PAYMENT for each row
BEGIN
    :new.amount_outstanding := :old.amount_outstanding - :new.amount_paid;
END;

Это уменьшает amount outstandingна сумму новейшего платежа.(Я предположил, что каждая запись в PROJECT_PAYMENT представляет один платеж, а amount_paid не является скользящим итогом.)

...