postgresql:触发导致错误的评估

时间:2016-10-18 11:24:59

标签: postgresql triggers

表格和架构设置

考虑以下表格和触发器,

CREATE TABLE t1 (
  c1 int,
  c2 text,
  c3 text,
  m1 int,
  m2 int,
  primary key (c1,c2,c3)    
);



CREATE TABLE t2 (
  c1 int,
  c2 text,
  c3 text,
  aggm int,
  primary key (c1,c2,c3)
);  

CREATE OR REPLACE FUNCTION aggregation_of_t1() RETURNS TRIGGER AS $t1$
    BEGIN
        INSERT INTO t2(c1, c2,c3,aggm) 
          VALUES (new.c1, new.c2, new.c3, new.m1 + new.m2) 
            ON CONFLICT (c1,c2,c3) 
            DO UPDATE SET aggm = t2.aggm + new.m1 + new.m2;
        RETURN NULL;
    END;
$t1$ LANGUAGE plpgsql;

CREATE TRIGGER aggregate_trigger AFTER INSERT OR UPDATE ON t1 FOR EACH ROW EXECUTE PROCEDURE aggregation_of_t1();

t1:主表包含c1,c2,c3标识符的m1,m2列(标记) t2:我希望这个表是m1和m2的聚合,用于t1中的所有唯一值(c1,c2,c3)。

问题

我看到t2(即aggm)中的聚合值对于我正在进行的每个插入都加倍。

输出

root=> select * from t1;
 c1 | c2 | c3 | m1 | m2
----+----+----+----+----
(0 rows)

root=> select * from t2;
 c1 | c2 | c3 | aggm
----+----+----+------
(0 rows)

root=> insert into  t1 (c1,c2,c3,m1,m2) values (113,'URL-1','ID-1',23,22) ON CONFLICT (c1,c2,c3) DO UPDATE SET m1 = t1.m1+23, m2 = t1.m2 + 22;
INSERT 0 1
root=> select * from t1;
 c1  |  c2   |  c3  | m1 | m2
-----+-------+------+----+----
 113 | URL-1 | ID-1 | 23 | 22
(1 row)

root=> select * from t2;
 c1  |  c2   |  c3  | aggm
-----+-------+------+------
 113 | URL-1 | ID-1 |   45
(1 row)

root=> insert into  t1 (c1,c2,c3,m1,m2) values (113,'URL-1','ID-1',10,11) ON CONFLICT (c1,c2,c3) DO UPDATE SET m1 = t1.m1+10, m2 = t1.m2 + 11;
INSERT 0 1
root=> select * from t2;
 c1  |  c2   |  c3  | aggm
-----+-------+------+------
 113 | URL-1 | ID-1 |  111
(1 row)

root=> select * from t1;
 c1  |  c2   |  c3  | m1 | m2
-----+-------+------+----+----
 113 | URL-1 | ID-1 | 33 | 33
(1 row)  

问题:我不期待t2中的值111。相反,我期待66在这里(即23 + 22(第一次插入)和10 + 11(第二次插入))。
我认为在第二次插入时它会将其视为45 + 45 + 21 = 111。

我在这里做的错误是什么?

1 个答案:

答案 0 :(得分:1)

new是写入您的表格的记录,其中m1m2都是33。

所以t2.aggm + new.m1 + new.m2是45 + 33 + 33 = 111。

要获得您想要的结果(例如aggm = 45 + 10 + 11),您应该将AFTER UPDATE案例移至单独的触发器,其中包含以下内容:

UPDATE t2 SET aggm = aggm + (new.m1 - old.m1) + (new.m2 - old.m2);