DB2 触发器新视图不反映以前触发器更新的数据

DB2 trigger new view doesn't reflect data updated by previous triggers

假设我创建了以下 tables:

create table SAMPLE (
    ID INTEGER,
    COL_A INTEGER,
    COL_B INTEGER
);
create table SAMPLE_CLONE (
    ID INTEGER,
    COL_A INTEGER,
    COL_B INTEGER
);

并且我创建了以下触发器:

-- Increment COL_A on every update
CREATE TRIGGER INC_COL_A AFTER UPDATE ON SAMPLE
REFERENCING  OLD AS oldrow  NEW AS newrow  
FOR EACH ROW MODE DB2SQL 
WHEN (oldrow.COL_A = newrow.COL_A)
UPDATE SAMPLE SET COL_A = COL_A+1 WHERE ID = oldrow.ID;

-- Replicate inserts from SAMPLE to SAMPLE_CLONE
CREATE TRIGGER REPLICATE_INSERTED_DATA
AFTER INSERT ON SAMPLE
REFERENCING NEW AS newrow
FOR EACH ROW MODE DB2SQL
INSERT INTO SAMPLE_CLONE (ID, COL_A, COL_B) VALUES (newrow.ID, newrow.COL_A, newrow.COL_B);

-- Replicate updates from SAMPLE to SAMPLE_CLONE
CREATE TRIGGER REPLICATE_UPDATED_DATA
AFTER UPDATE ON SAMPLE
REFERENCING NEW AS newrow OLD AS oldrow
FOR EACH ROW MODE DB2SQL
UPDATE SAMPLE_CLONE SET COL_A = newrow.COL_A, COL_B = newrow.COL_B WHERE ID = newrow.ID;

我遇到的问题是,在我 运行 对 SAMPLE table 进行任何更新后,触发器 INC_COL_A 增加的 COL_A 最新值不是在触发器 REPLICATE_UPDATED_DATA 处理期间反映到 newrow 中。例如,如果我有以下数据:

INSERT INTO SAMPLE (ID, COL_A, COL_B) VALUES (1, 1, 100);

样本

ID COL_A COL_B
1 1 100

SAMPLE_CLONE

ID COL_A COL_B
1 1 100

然后,在 运行 执行以下命令后:

UPDATE SAMPLE SET COL_B = 200 WHERE ID = 1;

我在这些 table 上得到以下结果:

样本

ID COL_A COL_B
1 2 200

SAMPLE_CLONE

ID COL_A COL_B
1 1 200

请注意 SAMPLE_CLONE.COL_A 上的记录没有被 REPLICATE_UPDATED_DATA 触发器复制,因为它没有得到 INC_COL_A 触发器所做的更新。

我在使用 DB2 11.5 时遇到了这个问题

这不是让更新(或插入)触发器更改正在写入的值的正确方法...您想使用 BEFORE 更新(插入)触发器

-- Increment COL_A on every update
CREATE TRIGGER INC_COL_A BEFORE UPDATE ON SAMPLE
REFERENCING  OLD AS oldrow  NEW AS newrow  
FOR EACH ROW MODE DB2SQL 
WHEN (oldrow.COL_A = newrow.COL_A)
 SET newrow.COL_A = oldrow.COL_A+1 ;

共享事件、时间和目标的触发器按创建顺序执行。每个 BEFORE 触发器都可以修改 NEW ROW,后续 BEFORE 触发器将使用修改后的行。每个 AFTER 个触发器都将收到相同的最后一行,其中 none 个可以修改它。

这里INC_COL_AREPLICATE_UPDATED_DATA是按照这个顺序执行的

所以当 UPDATE SAMPLE SET COL_B = 200 WHERE ID = 1; 是 运行

  1. DB2 使用 COLB_B = 200
  2. 生成一个中间行
  3. INC_COL_A被触发,执行UPDATE SAMPLE SET COL_A = 2
  4. 此更新再次触发 INC_COL_A,但由于 COL_A 在旧行和新行中相同,因此没有任何反应
  5. REPLICATE_UPDATED_DATACOL_A = 2, COL_B = 200 处理行并将其复制到 SAMPLE_CLONE
  6. INC_COL_A 中的 UPDATE 语句现已完成,但 REPLICATE_UPDATED_DATA 仍需处理 COL_A = 1, COL_B = 200

归根结底,COL_A = 1也是有逻辑的。在 INC_COL_A 之前创建 REPLICATE_UPDATED_DATA ,您的触发器将按预期工作。

检查实际行值是否与旧行值匹配是此处的解决方案,但可能不是您在实际应用中需要的。

CREATE TRIGGER REPLICATE_UPDATED_DATA
AFTER UPDATE ON SAMPLE
REFERENCING NEW AS newrow OLD AS oldrow
FOR EACH ROW MODE DB2SQL
UPDATE SAMPLE_CLONE SET COL_A = newrow.COL_A, COL_B = newrow.COL_B
  WHERE ID = newrow.ID
        and (col_a, col_b) = (old_row.col_a, old_row.col_b);