如何实现更新 "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
以便在 status
从 INSTOCK
更新到 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();
探索的另一种方法是接受 id
和 new_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)
如何更新 stolen_at
以便在 status
从 INSTOCK
更新到 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();
探索的另一种方法是接受 id
和 new_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)