Table 在 BEFORE DELETE 触发器上发生变化
Table is mutating on BEFORE DELETE trigger
基本上,我有这 2 tables:
CREATE TABLE Aposta (
codMovimento number(10)
references Movimento(codMovimento),
Primary key(codMovimento),
data DATE default sysdate not null,
valor Number(10,2) not null,
quotaTotal Number(10,2) not null,
CodTipoAposta Number(1) not null
references TipoAposta(CodTipoAposta)
CodEstadoAposta Number(1)
references EstadoAposta(CodEstadoAposta)
);
CREATE TABLE LinhaAposta (
CodMovimento Number(10)
references Movimento(CodMovimento),
CodEvento Number(10)
references Evento(CodEvento),
Primary key(CodMovimento,CodEvento),
quota Number(10,2) not null,
resultado VARCHAR2(1) not null
check (resultado in ('1','X','2'))
);
我创建了这个 BEFORE DELETE 触发器来将 quotaTotal 值除以要删除的配额值。它还需要根据 table linhaaposta 的行数更新 codTipoAposta 的值。我已经尝试过在删除后创建它,但在脚本输出中出现了同样的错误,并且还尝试使用 :NEW 而不是 :OLD。
触发器:
create or replace TRIGGER update_Quota_Estado2
BEFORE DELETE ON linhaaposta
FOR EACH ROW
DECLARE
updateCount number(3);
BEGIN
UPDATE Aposta SET quotaTotal= quotaTotal / :OLD.quota WHERE codMovimento = :OLD.codMovimento;
SELECT COUNT(*) INTO updateCount FROM linhaaposta WHERE codMovimento = :OLD.codMovimento;
IF (updateCount = '0') THEN
UPDATE Aposta SET codTipoAposta = 0 WHERE codMovimento = :OLD.codMovimento;
END IF;
IF (updateCount >= '1') THEN
UPDATE Aposta SET codTipoAposta = 1 WHERE codMovimento = :OLD.codMovimento;
END IF;
END;
我制作了一个类似的 BEFORE INSERT 触发器,它工作得很好但恰恰相反,将插入到配额上的值相乘并将其更新为 table Aposta 上的 quotaTotal。
这是触发器:
CREATE OR REPLACE TRIGGER update_Quota_Estado
BEFORE INSERT ON linhaaposta
FOR EACH ROW
DECLARE
updateCount number(3);
BEGIN
UPDATE Aposta SET quotaTotal= quotaTotal * :NEW.quota WHERE codMovimento = :NEW.codMovimento;
SELECT COUNT(*) INTO updateCount FROM linhaaposta WHERE codMovimento = :NEW.codMovimento;
IF (updateCount = '0') THEN
UPDATE Aposta SET codTipoAposta = 0 WHERE codMovimento = :NEW.codMovimento;
END IF;
IF (updateCount >= '1') THEN
UPDATE Aposta SET codTipoAposta = 1 WHERE codMovimento = :NEW.codMovimento;
END IF;
END;
每当第一个触发器被激活时,这是脚本输出:
Error starting at line : 22 in command -
DELETE FROM linhaaposta where codEvento=1
Error report -
ORA-04091: table LUIS.LINHAAPOSTA is mutating, trigger/function may not see it
ORA-06512: at "LUIS.UPDATE_QUOTA_ESTADO2", line 5
ORA-04088: error during execution of trigger 'LUIS.UPDATE_QUOTA_ESTADO2'
根据我的测试,它只从 SELECT 开始停止工作,在没有它和关联的 IFs 的情况下尝试它并且它工作。
缺少什么/我该怎么办?
您已命中 error ORA-04091。
您无法从触发器本身查询导致触发器触发的 table。这是 Oracle 设计的,以保护事务完整性。
如 , one solution is to use autonomous transaction 中所述。这通过在触发代码的 DECLARE
部分添加一个特定的 pragma 来实现;触发器操作发生在一个单独的数据库事务中,您必须在触发器代码的末尾提交,例如:
CREATE TRIGGER
...
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
...
COMMIT;
END;
基本上,我有这 2 tables:
CREATE TABLE Aposta (
codMovimento number(10)
references Movimento(codMovimento),
Primary key(codMovimento),
data DATE default sysdate not null,
valor Number(10,2) not null,
quotaTotal Number(10,2) not null,
CodTipoAposta Number(1) not null
references TipoAposta(CodTipoAposta)
CodEstadoAposta Number(1)
references EstadoAposta(CodEstadoAposta)
);
CREATE TABLE LinhaAposta (
CodMovimento Number(10)
references Movimento(CodMovimento),
CodEvento Number(10)
references Evento(CodEvento),
Primary key(CodMovimento,CodEvento),
quota Number(10,2) not null,
resultado VARCHAR2(1) not null
check (resultado in ('1','X','2'))
);
我创建了这个 BEFORE DELETE 触发器来将 quotaTotal 值除以要删除的配额值。它还需要根据 table linhaaposta 的行数更新 codTipoAposta 的值。我已经尝试过在删除后创建它,但在脚本输出中出现了同样的错误,并且还尝试使用 :NEW 而不是 :OLD。
触发器:
create or replace TRIGGER update_Quota_Estado2
BEFORE DELETE ON linhaaposta
FOR EACH ROW
DECLARE
updateCount number(3);
BEGIN
UPDATE Aposta SET quotaTotal= quotaTotal / :OLD.quota WHERE codMovimento = :OLD.codMovimento;
SELECT COUNT(*) INTO updateCount FROM linhaaposta WHERE codMovimento = :OLD.codMovimento;
IF (updateCount = '0') THEN
UPDATE Aposta SET codTipoAposta = 0 WHERE codMovimento = :OLD.codMovimento;
END IF;
IF (updateCount >= '1') THEN
UPDATE Aposta SET codTipoAposta = 1 WHERE codMovimento = :OLD.codMovimento;
END IF;
END;
我制作了一个类似的 BEFORE INSERT 触发器,它工作得很好但恰恰相反,将插入到配额上的值相乘并将其更新为 table Aposta 上的 quotaTotal。
这是触发器:
CREATE OR REPLACE TRIGGER update_Quota_Estado
BEFORE INSERT ON linhaaposta
FOR EACH ROW
DECLARE
updateCount number(3);
BEGIN
UPDATE Aposta SET quotaTotal= quotaTotal * :NEW.quota WHERE codMovimento = :NEW.codMovimento;
SELECT COUNT(*) INTO updateCount FROM linhaaposta WHERE codMovimento = :NEW.codMovimento;
IF (updateCount = '0') THEN
UPDATE Aposta SET codTipoAposta = 0 WHERE codMovimento = :NEW.codMovimento;
END IF;
IF (updateCount >= '1') THEN
UPDATE Aposta SET codTipoAposta = 1 WHERE codMovimento = :NEW.codMovimento;
END IF;
END;
每当第一个触发器被激活时,这是脚本输出:
Error starting at line : 22 in command -
DELETE FROM linhaaposta where codEvento=1
Error report -
ORA-04091: table LUIS.LINHAAPOSTA is mutating, trigger/function may not see it
ORA-06512: at "LUIS.UPDATE_QUOTA_ESTADO2", line 5
ORA-04088: error during execution of trigger 'LUIS.UPDATE_QUOTA_ESTADO2'
根据我的测试,它只从 SELECT 开始停止工作,在没有它和关联的 IFs 的情况下尝试它并且它工作。 缺少什么/我该怎么办?
您已命中 error ORA-04091。
您无法从触发器本身查询导致触发器触发的 table。这是 Oracle 设计的,以保护事务完整性。
如 DECLARE
部分添加一个特定的 pragma 来实现;触发器操作发生在一个单独的数据库事务中,您必须在触发器代码的末尾提交,例如:
CREATE TRIGGER
...
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
...
COMMIT;
END;