仅更新 1 行时,PostgreSQL 更新触发器会多次触发
PostgreSQL Update TRIGGER Fires Multiple Times When Just 1 Row Updated
来源Table:-
CREATE TABLE schema1.Source_Table
(
Source_Table_id serial NOT NULL,
current_status_id smallint NOT NULL,
current_status_reason varchar(200) NULL,
requestor_id integer NOT NULL,
approver_id integer NULL,
last_upd_user_id integer NOT NULL,
last_upd_date_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT PK_Source_Table PRIMARY KEY (Source_Table_id)
)
WITH OIDS;
目的地Table(审计历史目的):-
CREATE TABLE schema2.Destination_Table
(
type_id smallint NOT NULL,
id integer NOT NULL,
state_id smallint NOT NULL,
state_reason varchar(200) NULL,
requestor_id integer NOT NULL,
approver_id integer NULL,
upd_by_user_id integer NOT NULL,
upd_by_user_type smallint NOT NULL,
upd_date_time timestamp without time zone NOT NULL
)
WITH OIDS;
源上的每个行触发器更新后 Table:-
CREATE TRIGGER trg_upd_Source_Table
AFTER UPDATE of current_status_id
ON schema1.Source_Table
FOR EACH ROW
WHEN (OLD.current_status_id IS DISTINCT FROM NEW.current_status_id)
EXECUTE PROCEDURE schema1.Source_Table_hist();
上面每行触发器更新后的触发函数:-
CREATE OR REPLACE FUNCTION schema1.Source_Table_hist()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
INSERT INTO schema2.Destination_Table
(type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id,
upd_by_user_type, upd_date_time)
SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason,
OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
from schema1.Source_Table
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
RETURN NULL;
END;
$$
在 schema1.Source_Table table 中已经有 8 行具有唯一的主键 Source_Table_id。
当我使用主键如下所示仅更新此 table 的 1 行时,它会将 8 行(1 行原始行和 7 行重复行)插入 schema2.Destination_Table table 而不是仅 1 行。
update schema1.Source_Table
set current_status_id = 4
where Source_Table_id = 9;
这里的问题是:-
为什么触发器触发 8 次(等于创建此触发器的 table 中的总行数),而 table 中只有 1 行被更新。
预期行为:-
当在创建触发器的源 table 中仅更新 1 行时,触发器应仅触发一次,然后在目标审计 table 中插入 1 行。
如何解决这个问题?
触发器未触发多次,您的查询正在为源 table 中的每一行向历史 table 中插入一行 table:
INSERT INTO schema2.Destination_Table
(type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id,
upd_by_user_type, upd_date_time)
SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason,
OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
from schema1.Source_Table
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
RETURN NULL;
我认为您不需要那个 from 子句。
问题出在WHERE条件:
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id
从触发器的 WHEN 条件得知此条件为真。因为它是唯一有效的 WHERE 条件,所以根本没有 WHERE 条件,因此所有 roes 都由插入处理。建议
where current_status_id = OLD.current_status_id
来源Table:-
CREATE TABLE schema1.Source_Table
(
Source_Table_id serial NOT NULL,
current_status_id smallint NOT NULL,
current_status_reason varchar(200) NULL,
requestor_id integer NOT NULL,
approver_id integer NULL,
last_upd_user_id integer NOT NULL,
last_upd_date_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT PK_Source_Table PRIMARY KEY (Source_Table_id)
)
WITH OIDS;
目的地Table(审计历史目的):-
CREATE TABLE schema2.Destination_Table
(
type_id smallint NOT NULL,
id integer NOT NULL,
state_id smallint NOT NULL,
state_reason varchar(200) NULL,
requestor_id integer NOT NULL,
approver_id integer NULL,
upd_by_user_id integer NOT NULL,
upd_by_user_type smallint NOT NULL,
upd_date_time timestamp without time zone NOT NULL
)
WITH OIDS;
源上的每个行触发器更新后 Table:-
CREATE TRIGGER trg_upd_Source_Table
AFTER UPDATE of current_status_id
ON schema1.Source_Table
FOR EACH ROW
WHEN (OLD.current_status_id IS DISTINCT FROM NEW.current_status_id)
EXECUTE PROCEDURE schema1.Source_Table_hist();
上面每行触发器更新后的触发函数:-
CREATE OR REPLACE FUNCTION schema1.Source_Table_hist()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
INSERT INTO schema2.Destination_Table
(type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id,
upd_by_user_type, upd_date_time)
SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason,
OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
from schema1.Source_Table
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
RETURN NULL;
END;
$$
在 schema1.Source_Table table 中已经有 8 行具有唯一的主键 Source_Table_id。 当我使用主键如下所示仅更新此 table 的 1 行时,它会将 8 行(1 行原始行和 7 行重复行)插入 schema2.Destination_Table table 而不是仅 1 行。
update schema1.Source_Table
set current_status_id = 4
where Source_Table_id = 9;
这里的问题是:- 为什么触发器触发 8 次(等于创建此触发器的 table 中的总行数),而 table 中只有 1 行被更新。
预期行为:- 当在创建触发器的源 table 中仅更新 1 行时,触发器应仅触发一次,然后在目标审计 table 中插入 1 行。
如何解决这个问题?
触发器未触发多次,您的查询正在为源 table 中的每一行向历史 table 中插入一行 table:
INSERT INTO schema2.Destination_Table
(type_id, id, state_id, state_reason, requestor_id, approver_id, upd_by_user_id,
upd_by_user_type, upd_date_time)
SELECT 1, OLD.Source_Table_id, OLD.current_status_id, OLD.current_status_reason,
OLD.requestor_id, OLD.approver_id, OLD.last_upd_user_id, 1, OLD.last_upd_date_time
from schema1.Source_Table
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id;
RETURN NULL;
我认为您不需要那个 from 子句。
问题出在WHERE条件:
where OLD.current_status_id IS DISTINCT FROM NEW.current_status_id
从触发器的 WHEN 条件得知此条件为真。因为它是唯一有效的 WHERE 条件,所以根本没有 WHERE 条件,因此所有 roes 都由插入处理。建议
where current_status_id = OLD.current_status_id