在普通 SQL 中访问触发器函数中的旧/新表值

eCo*_*Evo 7 postgresql functions postgresql-9.6

我正在尝试构建一个触发器函数,以便在任何项目发生更改时自动更新父订单值。

这是我创建的:

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();
Run Code Online (Sandbox Code Playgroud)

当我尝试运行它时,出现此错误:

missing FROM-clause for table "old"
Run Code Online (Sandbox Code Playgroud)

我尝试在触发器中创建对原始表的引用:

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();
Run Code Online (Sandbox Code Playgroud)

但这只是给出了错误syntax error at or near "REFERENCING"

如何order_id从原始order_items表中获取?

Lua*_*ynh 8

首先,在其上创建一个触发器order_items表中,update_totals()必须是一个触发功能,其RETURNS TRIGGER粗体是矿)。

数据更改触发器被声明为没有参数且返回类型为 trigger的函数。请注意,即使函数希望接收 CREATE TRIGGER 中指定的某些参数,必须声明该函数 不带参数

如果不是,它会导致错误ERROR: function func_order_items must return type trigger

其次,请记住,你不能OLDAFTER INSERT上了扳机。如果不是,它会引发错误ERROR: record "old" is not assigned yet

最后,请看下面的例子:

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);
Run Code Online (Sandbox Code Playgroud)

  • 我还要补充一点,即您不能使用纯 SQL 作为触发器函数的语言。 (5认同)