web-dev-qa-db-fra.com

Accès à la valeur de la table OLD / NEW dans une fonction de déclenchement en SQL simple

J'essaie de créer une fonction de déclenchement pour mettre à jour automatiquement les valeurs de la commande parent à chaque fois que l'un de ses éléments change.

Voici ce que j'ai créé:

CREATE OR REPLACE FUNCTION update_totals() RETURNS void AS $$
    UPDATE orders SET
       total_fees = (SELECT SUM(fees) FROM order_items WHERE order_id = OLD.order_id),
       total_profit = (CASE WHEN total_cost IS NOT NULL THEN total - total_tax - total_cost - (SELECT SUM(fees) FROM order_items WHERE order_id = OLD.order_id) ELSE NULL END)
    WHERE id = OLD.order_id;
$$
LANGUAGE SQL;

CREATE TRIGGER update_totals AFTER INSERT 
OR UPDATE OF fees
ON order_items INITIALLY DEFERRED
FOR EACH ROW
WHEN ( OLD.* IS DISTINCT FROM NEW.* ) EXECUTE PROCEDURE update_totals();

Lorsque j'essaie d'exécuter cela, j'obtiens cette erreur:

missing FROM-clause for table "old"

J'ai essayé de créer une référence à la table d'origine dans le déclencheur:

CREATE TRIGGER update_totals AFTER INSERT 
OR UPDATE OF fees
ON order_items
REFERENCING OLD ROW AS old_order
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
WHEN ( OLD.* IS DISTINCT FROM NEW.* ) EXECUTE PROCEDURE update_totals();

Mais cela donne juste l'erreur syntax error at or near "REFERENCING".

Comment obtenir le order_id de l'original order_items table?

5
eComEvo

Tout d'abord , pour créer un déclencheur sur la table order_items, La update_totals() doit être un déclencheur fonction qui RETURNS TRIGGER ( gras est le mien).

Un déclencheur de changement de données est déclaré comme une fonction sans arguments et un type de déclencheur de retour . Notez que la fonction doit être déclarée avec aucun argument même si elle s'attend à recevoir certains arguments spécifiés dans CREATE TRIGGER

Sinon, cela provoque une erreur ERROR: function func_order_items must return type trigger.

Deuxièmement , n'oubliez pas que vous ne pouvez pas avoir OLD lorsque AFTER INSERT Sur le déclencheur. Sinon, il déclenche une erreur ERROR: record "old" is not assigned yet.

Enfin , veuillez consulter l'exemple ci-dessous:

CREATE TABLE IF NOT EXISTS orders(ID INT NOT NULL PRIMARY KEY, X INT);
CREATE TABLE IF NOT EXISTS order_items (ID INT NOT NULL PRIMARY KEY, ORDER_ID INT, Y INT); 

INSERT INTO orders VALUES(1, 0);
INSERT INTO order_items VALUES(10, 1, 20);
INSERT INTO order_items VALUES(11, 1, 30);

CREATE OR REPLACE FUNCTION func_order_items() RETURNS trigger AS 
$$
BEGIN
  IF (TG_OP = 'UPDATE') THEN
    UPDATE orders
    SET X = (SELECT SUM(Y) FROM order_items WHERE order_id = OLD.order_id)
    WHERE ID = OLD.order_id;
  ELSIF (TG_OP = 'INSERT') THEN
    UPDATE orders
    SET X = (SELECT SUM(Y) FROM order_items WHERE order_id = NEW.order_id)
    WHERE ID = NEW.order_id;
  END IF;
  RETURN NULL;
END
$$
LANGUAGE PLPGSQL;

CREATE TRIGGER trigger_order_items 
AFTER INSERT OR UPDATE 
ON order_items 
FOR EACH ROW EXECUTE PROCEDURE func_order_items();

UPDATE order_items SET Y = 200 WHERE ID = 10;
INSERT INTO order_items VALUES (12, 1, 200);
5
Luan Huynh