PostgreSQL多个触发器和函数

时间:2016-09-25 17:04:46

标签: sql postgresql triggers

我有以下表格。

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        
);

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

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. 最好只有一个函数首先检查“活动”字段,如果它继续,那么做历史记录吗?所以我只有1个(更大的)功能,只有1个触发器。
  3. 一切功能:

     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$
    

    考虑到性能,代码维护以及类似内容的任何想法?

1 个答案:

答案 0 :(得分:2)

两个问题。 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();

接下来,id中的tbl_groups_history应为序列号:

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,则该行的操作将被放弃,并且不会触发后续触发器(对于该行)。