oracle - 我如何通过触发器修复这个变异表

标签 oracle plsql triggers mutating-table

此触发器会将插入的值传递给一个过程,该过程将这些值插入另一个表中。我收到一个变异表错误。我怎样才能解决这个问题?

CREATE OR REPLACE TRIGGER ADD_INVOICE
BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN

POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE);

END;
/

CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE)
AS
CURSOR C_POP IS SELECT PRICE FROM TREATMENT T,APPOINTMENT A 
WHERE T.TRT_NO=A.TRT_NO
AND A.APP_NO=I_APP_NO;

V_BILL INVOICE.BILL%TYPE;
BEGIN

OPEN C_POP; 
FETCH C_POP INTO V_BILL;

UPDATE INVOICE
SET INV_NO=INV_IDSEQ.NEXTVAL,
APP_NO=I_APP_NO,
C_NO=I_C_NO,
BILL=V_BILL,
INV_DATE=I_INV_DATE;

END;
/

最佳答案

该问题是由在触发器本身内引用带有触发器的表引起的。更改过程以接受 TRT_NO 作为参数消除了在查询中包含 APPOINTMENT 的需要,因此将避免变异表异常。根据每个处理有多少记录,您甚至可以将游标合并到您的 UPDATE 语句中。

我认为应该这样做,尽管我无法检查数据库。

CREATE OR REPLACE TRIGGER ADD_INVOICE

BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN

POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE,:NEW.TRT_NO);

END;
/

修改后的程序:
CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE,
I_TRT_NO IN APPOINTMENT.TRT_NO%TYPE
)
AS

CURSOR C_POP IS SELECT PRICE 
FROM TREATMENT T
WHERE T.TRT_NO = I_TRT_NO;

V_BILL INVOICE.BILL%TYPE;

BEGIN

OPEN C_POP; 
FETCH C_POP INTO V_BILL;
CLOSE C_POP;

INSERT INVOICE
  (inv_no, app_no, c_no, bill, inv_date)
VALUES
  (INV_IDSEQ.NEXTVAL, I_APP_NO, I_C_NO, V_BILL, I_INV_DATE);


END;
/

关于oracle - 我如何通过触发器修复这个变异表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13519103/

相关文章:

mysql - SQL - 如果这不是真的,我可以做其他事情吗?

plsql - 使用带有绑定(bind)变量的 Execute Immediate 语句时出现无效的表名错误

c# - WPF 用户控件;触发器和更改其他控件

用于插入和更新的 MySQL Fire 触发器

java - Spring Boot Actuator/health 端点不显示数据库或文件系统信息

java - 比例大小无效。不能小于零

sql - 在 Oracle 中删除大量数据

sql - 如何从 PL/SQL 函数或过程内部访问 Oracle 系统表?

MYSQL - 用于将 VARCHAR 中的时间转换为 INTEGER 中的秒的触发器正在插入多行,而它应该只插入

java - 显示 SDO_GEOMETRY 类型属性的值