表在DELETE触发器之前发生变异

时间:2019-01-02 23:43:53

标签: sql oracle triggers mutating-table

基本上,我有以下两个表:

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值除以要删除的配额值。它还需要根据表linhaaposta的行数更新codTipoAposta的值。我已经尝试过将其设置为DELETE DELETE,但脚本输出中会显示相同的错误,并且还尝试了: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触发器,可以很好地工作,但反之,将配额上插入的值相乘,并将其更新为表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以后停止工作,在没有它和IF的情况下进行了尝试,并且可以工作。 缺少什么/我该怎么办?

1 个答案:

答案 0 :(得分:0)

您已击中error ORA-04091

您无法从触发器本身内部查询导致触发器触发的表。这是Oracle设计的,目的是保护事务的完整性。

this other SO post中所述,一种解决方案是使用autonomous transaction。这可以通过在触发代码的DECLARE部分中添加特定的编译指示来实现;触发操作发生在单独的数据库事务中,您必须在触发代码的末尾提交,例如:

CREATE TRIGGER
    ...
DECLARE
    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    ...
    COMMIT;
END;