Postgresql - 触发器添加两次

时间:2013-06-15 23:16:57

标签: sql postgresql triggers

我的表中有很多触发器,但其中一个触发器的行为并不完全像我想要的那样。

这个计算产品和价格并返回订单的总价格 - 工作正常:

CREATE OR REPLACE FUNCTION ustawwartosczamowienia() RETURNS TRIGGER AS $$

DECLARE

przed NUMERIC;
po NUMERIC;
ile NUMERIC;


BEGIN
IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN

SELECT cena*zamowienieilosc INTO ile FROM zamowienie_zawiera INNER JOIN zamowienie on zamowienie.id=zamowienie_idzamowienie inner join egzemplarz on zamowienie_zawiera.egzemplarz_idegzemplarz=egzemplarz.id inner join produkt on egzemplarz.produkt_idprodukt = produkt.id WHERE zamowienieilosc = new.zamowienieilosc;

SELECT wartosczamowienia INTO przed FROM zamowienie WHERE zamowienie.id = new.zamowienie_idzamowienie;


po := przed+ile;
UPDATE zamowienie SET wartosczamowienia=po WHERE zamowienie.id = new.zamowienie_idzamowienie;

ELSE
RAISE NOTICE 'Nie ma czegoś takiego';

END IF;

RETURN NEW;

END
$$
LANGUAGE 'plpgsql';


CREATE TRIGGER zamowieniewartosc
AFTER INSERT OR UPDATE
ON zamowienie_zawiera
FOR EACH ROW
EXECUTE PROCEDURE ustawwartosczamowienia();

然后我看到有人为f.e.购买了商品。总共1024。所以我想把这笔钱存入这个人的个人账户,以便以后为忠诚的客户提供特别优惠。我写了类似的触发器:

CREATE OR REPLACE FUNCTION kontododaj() RETURNS TRIGGER AS $$

DECLARE

przed NUMERIC;
po NUMERIC;
ile NUMERIC;

klient_idklient RECORD;


BEGIN
IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN

SELECT sumazamowien INTO przed FROM klient WHERE klient.id = new.klient_idklient; 

SELECT wartosczamowienia INTO ile FROM zamowienie WHERE wartosczamowienia =  new.wartosczamowienia; 

po := przed + ile;

UPDATE klient SET sumazamowien=po WHERE klient.id = new.klient_idklient;

ELSE
RAISE NOTICE 'Nie ma czegoś takiego';

END IF;
RETURN NEW;

END
$$
LANGUAGE 'plpgsql';


CREATE TRIGGER kontoplus
AFTER INSERT OR UPDATE
ON zamowienie
FOR EACH ROW
EXECUTE PROCEDURE kontododaj();

然后我查看某人的帐户,他们有2048而不是1024.我的触发器增加了两倍钱。我应该改变什么?

2 个答案:

答案 0 :(得分:1)

在不了解数据库结构的情况下找到原因是不安的,即。表格的DDL和可能发挥作用的其他触发器的代码。

你写道“我的桌子上有很多触发器”,我怀疑它们之间存在一些链接反应。如果是这种情况,我建议使用非触发程序来实现类似的逻辑。

顺便说一下,函数kontododaj()中可能存在逻辑错误。但在指出特定的地方之前,让我简化代码。来自kontododaj()身体:

IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN

    SELECT  sumazamowien
    INTO    przed
    FROM    klient
    WHERE   klient.id = new.klient_idklient; 

    SELECT  wartosczamowienia
    INTO    ile
    FROM    zamowienie
    WHERE   wartosczamowienia = new.wartosczamowienia; 

    po := przed + ile;

    UPDATE  klient
    SET     sumazamowien = po
    WHERE   klient.id = new.klient_idklient;

ELSE
    ...

以上代码段(以逻辑方式)等同于:

IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN

    UPDATE  klient
    SET     sumazamowien = sumazamowien + new.wartosczamowienia
    WHERE   klient.id = new.klient_idklient;

ELSE
    ...

现在,我怀疑这段代码应该在更新后执行。考虑当具有值1024的字段“wartosczamowienia”(订单的值)被设置为相同值1024时的情况。这将导致将1024添加到“sumazamowien”(订单的总值),这是错误的。 也许你应该这样试试:

IF      TG_OP = 'INSERT'
THEN

    UPDATE  klient
    SET     sumazamowien = sumazamowien + new.wartosczamowienia
    WHERE   klient.id = new.klient_idklient;

ELSIF   TG_OP = 'UPDATE'
    AND new.wartosczamowienia <> old.wartosczamowienia
THEN

    UPDATE  klient
    SET     sumazamowien = sumazamowien + ( new.wartosczamowienia - old.wartosczamowienia )
    WHERE   klient.id = new.klient_idklient;

ELSE
    ...

答案 1 :(得分:0)

一个很可能的原因是你在一个表zamowienie上创建了两个触发器。 可以将多个触发器分配给PostgresSQL中的一个表。这与我之前使用的其他数据库不同。我刚刚遇到这个问题并解决了。

通过: SELECT * FROM pg_trigger; 您可以看到分配给表的触发器。删除不必要的触发器,就可以了。