0

テーブルに多くのトリガーがありますが、意図したとおりに動作しないトリガーが 1 つあります。

これは製品と価格をカウントし、注文の合計価格を返します-正常に動作します:

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();

そして、誰かが完全に 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();

次に、誰かの口座を確認すると、1024 ではなく 2048 になっています。私のトリガーは、お金を 2 回追加します。何を変更すればよいですか?

4

2 に答える 2

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 に設定されている状況を考えてみましょう。これにより、「sumazamowien」(注文の合計値) に 1024 が追加されますが、これは誤りです。多分あなたはこの方法を試してみるべきです:

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
    ...
于 2013-06-16T09:57:36.333 に答える