【问题标题】:PostgreSQL multiple triggers and functionsPostgreSQL 多个触发器和函数
【发布时间】:2016-09-25 17:04:46
【问题描述】:

我有以下表格。

tbl_groups 包含所有当前数据,当名称发生变化时,我会将其存储在历史记录表中。

CREATE TABLE tbl_groups (
    id integer NOT NULL,
    name varchar NOT NULL,
    active boolean NOT NULL
);

CREATE TABLE tbl_groups_history (
    id integer NOT NULL,
    group_id integer NOT NULL,
    name varchar NOT NULL        
);

当活动字段为假时,可能不会发生更新。所以我为此创建了一个触发器,以便在发生这种情况时抛出异常:

CREATE OR REPLACE FUNCTION fn_group_deny_update_when_inactive() RETURNS TRIGGER AS
$BODY$
    BEGIN
        IF 
            OLD.active = false
        THEN 
            RAISE EXCEPTION 'Record is inactive';
        END IF;
        RETURN NEW;
    END;
$BODY$
LANGUAGE plpgsql;

CREATE TRIGGER 01_group_can_update
BEFORE UPDATE ON tbl_groups
FOR EACH ROW
EXECUTE PROCEDURE fn_group_deny_update_when_inactive();

我还有一个将记录写入历史表的触发器

CREATE OR REPLACE FUNCTION fn_group_log_history() RETURNS trigger as 
$BODY$
    BEGIN
        IF
           (NEW.name <> OLD.name)       
        THEN
            INSERT INTO tbl_groups_history (group_id, name)
            VALUES (OLD.id, OLD.name);
        END IF;
        RETURN NEW;
    END;
$BODY$
LANGUAGE plpgsql;

CREATE TRIGGER 02_group_write_history_log
BEFORE UPDATE ON tbl_groups
FOR EACH ROW
EXECUTE PROCEDURE fn_group_log_history();

我已将触发器命名为 01 和 02 作为前缀,因此我知道当 PostgreSQL 按字母顺序触发它们时它们将按什么顺序执行。

我对这种方法有一些疑问,因为我不确定这是否是好的做法:

  1. 是否可以在 tbl_groups 触发器上设置一个 BEFORE UPDATE 触发器,以特定顺序执行这 2 个函数?
  2. 最好只有一个函数先检查“活动”字段,如果继续,做历史记录吗?所以我将只有 1 个(更大的)函数和 1 个触发器。

一切尽在一个功能中:

 CREATE OR REPLACE FUNCTION fn_group_before_update() RETURNS trigger as 
$BODY$
    BEGIN
        IF 
            OLD.active = false
        THEN 
            RAISE EXCEPTION 'Record is inactive';
        END IF;
        IF
           (NEW.name <> OLD.name)       
        THEN
            INSERT INTO tbl_groups_history (group_id, name)
            VALUES (OLD.id, OLD.name);
        END IF;
        RETURN NEW;
    END;
$BODY$

考虑到性能、代码维护和类似的东西,对此有什么想法吗?

【问题讨论】:

    标签: sql postgresql triggers


    【解决方案1】:

    两个问题。 01_group_can_update 不是一个专有名称,因此请更改此名称,例如:

    CREATE TRIGGER trg_01_group_can_update
    BEFORE UPDATE ON tbl_groups
    FOR EACH ROW
    EXECUTE PROCEDURE fn_group_deny_update_when_inactive();
    

    接下来,tbl_groups_history 中的id 应该是串行的:

    CREATE TABLE tbl_groups_history (
        id serial NOT NULL,
        group_id integer NOT NULL,
        name varchar NOT NULL        
    );
    

    在您的情况下没有理由使用多个触发器,因此第二种解决方案似乎更好。但是,第一个变体也应该起作用。每the documentation

    如果为同一关系上的同一事件定义了多个触发器,则触发器将按触发器名称的字母顺序触发。在 BEFORE 和 INSTEAD OF 触发器的情况下,每个触发器返回的可能修改的行将成为下一个触发器的输入。如果任何 BEFORE 或 INSTEAD OF 触发器返回 NULL,则放弃该行的操作,并且不会触发后续触发器(针对该行)。

    【讨论】:

    • 有趣的是,如果触发器返回 NULL,操作将被放弃,我错过了那部分。因此,如果我有多个触发器,那么在某处搜索可能的错误会更费力。我有一种感觉,多个触发器对于这个目的来说有点太多了。对于触发器的名称,您是对的,这更好。我还在函数前面加上了 fn_,所以我必须在触发器上加上 trg_
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-14
    相关资源
    最近更新 更多