使用触发器时如何避免突变 table 错误?

How to avoid mutating table error while using a trigger?

我需要在 Table_A 中插入行,其中值来自 Table_B Table_B 的 UPDATE。

table_A (
station int,
state   varchar(20),
CONSTRAINT pk_table_a PRIMARY KEY(station, state),
CONSTRAINT fk_table_A FOREIGN KEY (station, state)
    REFERENCES table_B (station, state)
)

table_B (
station int,
state   varchar(20),
player  int,
date_sent Date DEFAULT NULL
CONSTRAINT pk_table_b PRIMARY KEY(station, state, player)
)

现在,当这些 (station, state) 的所有日期都变成 table_B 中的 NOT NULL 时,我的触发器需要向 table_A (station, state) 添加一行。

这是我的实际原因 mutating table error:

CREATE OR REPLACE TRIGGER add_stations_sent
    AFTER INSERT OR UPDATE ON "TABLE_B"
    FOR EACH ROW
    WHEN (NEW.DATE_SENT IS NOT NULL)
DECLARE
    nb_stations_null number;
BEGIN
    SELECT COUNT(1)
    INTO nbr_stations_null
    FROM "TABLE_B"
    WHERE "TABLE_B".STATE = :NEW.STATE AND
          "TABLE_B".STATION <> :NEW.STATION AND
          "TABLE_B".DATE_SENT IS NULL;

    IF (nb_stations_null = 0) THEN
        INSERT INTO "TABLE_A" VALUES (:NEW.STATION, :NEW.STATE);
    END IF;
END;

这样的事情会将处理推迟到 AFTER STATEMENT 级别,从而允许您 运行 查询

create or replace 
trigger avoid_mutate
for insert or update on table_b
compound trigger

  l_station sys.odcivarchar2list := sys.odcivarchar2list();
  l_state   sys.odcivarchar2list := sys.odcivarchar2list();

  before each row is
  begin
    l_station.extend;
    l_state.extend;
    l_station(l_station.count) := :new.station;
    l_state(l_state.count)     := :new.state;
  end before each row;

  after statement is
  declare
    nb_stations_null number;
  begin
    for i in 1 .. l_station.count loop
      SELECT COUNT(1)
      INTO nbr_stations_null
      FROM "TABLE_B"
      WHERE "TABLE_B".STATE = l_state(i) AND
            "TABLE_B".STATION <> l_station(i) AND
            "TABLE_B".DATE_SENT IS NULL;    
            
    IF (nb_stations_null = 0) THEN
        INSERT INTO "TABLE_A" VALUES (l_station(i), l_state(i));
    END IF;
    
  end after statement;

end;
/