我有一个必须为作业创建的小型系统。这意味着可以更轻松地查看数据库中的相关数据以进行“管理”。
我有三个表:
CLIENT
仅包含客户端ID,客户端名称,电话号码和电子邮件。
PROJECT
很简单。它具有项目ID,引用CLIENT
的客户端ID和项目名称。
PROJECT_PAYMENT
包含项目付款ID,引用PROJECT
的项目ID,然后包含具有付款到期日,已付款金额,未清金额等的行负载。
然后我有四个视图:
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:
我在Google周围搜索,发现添加了以下内容:
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSATION;
...可以在“ BEGIN”行上方使用,但是现在我遇到了“权限不足”错误:
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
答案 0 :(得分:2)
视图是永久数据库结构。就像编写表或其他任何东西一样,只需编写DDL脚本即可。运行它们一次,然后将视图特权授予需要访问权限的人员。乔布斯是个好人。
除了任何其他内容,您都不想每次有人记录项目付款时都重新创建那些对象。获取对象锁将是一件令人头疼的事,并且由于会话状态无效,用户试图查询那些视图的尝试会不断失败。
要解释您遇到的错误:
Oracle中的ORA-04092:无法在触发器中提交
DDL(例如CREATE VIEW语句)发出隐式提交。 Oracle不允许我们在触发器中包括COMMIT(或ROLLBACK),因为触发器作为事务的一部分触发,但是触发时不一定完成事务。
ORA-01031:特权不足
看起来您具有通过角色授予的CREATE VIEW特权。我们不能使用通过程序单位中的角色(存储过程,视图或触发器)间接授予的角色。
作业指定我必须证明如何使用过程,函数和触发器。
使用触发器创建视图并不能证明您知道“如何使用过程,函数和触发器” 。实际上相反。
触发器的一种更简单,更好的用法是使用amount paid
来维护PROJECT_PAYMENT上的amount outstanding
。
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
不是滚动总额。)