如何实现更新 "status" 字段时填充的 "stolen_at" 字段? TRIGGER 函数和 GENERATED ALWAYS AS 附加尝试

How to acheive a "stolen_at" field which is populated when the "status" field is updated? TRIGGER function and GENERATED ALWAYS AS attempts attached

如何更新 stolen_at 以便在 statusINSTOCK 更新到 STOLEN 时填充当前时间戳?

我已经尝试过基于触发器的方法,但它包含一个错误:

SQL Error [2F005]: ERROR: control reached end of trigger procedure without RETURN
  Where: PL/pgSQL function stolen()

触发方式:

CREATE TABLE items ( 
    id INTEGER PRIMARY KEY, 
    item_name text NOT NULL, 
    item_status text NOT NULL, 
    stolen_at TIMESTAMP WITHOUT TIME zone 
);


CREATE OR REPLACE FUNCTION stolen() RETURNS TRIGGER AS $CODE$ 
BEGIN
   -- Populate stolen_at with datetime only if item_status 
   -- changes from INSTOCK to STOLEN
   IF NEW.item_status = 'STOLEN' 
   AND OLD.item_status = 'INSTOCK' 
   THEN
      NEW.stolen_at : = now() AT TIME zone 'utc';
   END IF;
END $CODE$ LANGUAGE plpgsql;


CREATE TRIGGER populate_stoken 
AFTER INSERT OR UPDATE OF item_status 
ON items FOR EACH ROW EXECUTE PROCEDURE stolen();
   

探索的另一种方法是接受 idnew_item_status 并填充 item_status 字段的函数。虽然我无法让它工作:

CREATE TABLE items ( 
    id INTEGER PRIMARY KEY, 
    item_name text NOT NULL, 
    item_status text NOT NULL, 
    stolen_at TIMESTAMP WITHOUT TIME zone NOT NULL GENERATED ALWAYS AS (stolen2(id, item_status)) STORED 
);

CREATE OR REPLACE FUNCTION stolen2(id INT, new_item_status text) RETURNS TIMESTAMP AS $CODE$ 
DECLARE stolen_at TIMESTAMP WITHOUT TIME zone;
BEGIN
   SELECT
      * 
   FROM
      items 
   WHERE
      id = id 
      AND item_status = 'INSTOCK';      
      
   -- Return if conditions satisfy otherwise return null 
   IF found AND new_item_status = 'STOLEN' 
   THEN
      RETURN now() AT TIME zone 'utc';
   ELSE
      RETURN NULL;
END IF;
END $CODE$ LANGUAGE plpgsql;

这两种方法中哪一种是首选(例如,资源密集度较低)以及实施它们的正确方法是什么?

您的第一个触发器几乎没问题,但有两处错误:

  • 它必须是一个 BEFORE 触发器,以便您可以修改新行

  • 您在决赛 END; 之前错过了 RETURN NEW;(有关讨论,请参阅 here