删除前触发,不删除表中的数据

时间:2019-06-11 13:04:56

标签: sql postgresql

当修改/删除一行时,我正在处理数据库的历史记录。 我的主表是“ bati”,历史表是“ bati_history”,当删除或修改一行时,触发器应该将所有旧数据插入到bati_history中,然后在主表(bati)中删除。但是使用我的代码,该行将插入到历史记录中,但不会在主表中删除,并且我不知道为什么。

我使用的是PostgreSQL 11.2 64位

代码:

主表:

CREATE TABLE IF NOT EXISTS bati(
    id_bati BIGSERIAL NOT NULL UNIQUE,
    code_bati VARCHAR(25) NOT NULL,
    code_parcelle CHAR(50) NOT NULL,
    ...);

历史记录表:

CREATE TABLE IF NOT EXISTS bati_history(
    id_history BIGSERIAL NOT NULL PRIMARY KEY,
    event CHAR(10) NOT NULL,
    date_save_history TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    id_bati BIGINT NOT NULL,
    code_bati VARCHAR(25) NOT NULL,
    code_parcelle CHAR(50) NOT NULL,
        ...);

功能

CREATE FUNCTION archive_bati() RETURNS TRIGGER AS $BODY$
  BEGIN
    IF (TG_OP = 'DELETE') THEN
      INSERT INTO bati_history (event,id_bati,code_bati,code_parcelle,...)
      VALUES ('DELETE',OLD.id_bati,OLD.code_bati,OLD.code_parcelle,OLD....);
    ELSIF (TG_OP = 'UPDATE') THEN
      INSERT INTO bati_history (event,id_bati,code_bati,code_parcelle,...)
      VALUES ('UPDATE',OLD.id_bati,OLD.code_bati,OLD.code_parcelle,OLD....);
    END IF;
    RETURN NEW;
  END;
$BODY$
LANGUAGE 'plpgsql';

触发器:

CREATE TRIGGER bati_trigger_before_delete BEFORE DELETE
ON bati FOR EACH ROW
EXECUTE PROCEDURE archive_bati();

CREATE TRIGGER bati_trigger_before_update BEFORE UPDATE
ON bati FOR EACH ROW
EXECUTE PROCEDURE archive_bati();

当我尝试DELETE FROM bati;时,我希望复制bati_history中的每一行,然后将其从bati中删除,但是它们并不是从bati中删除,因此我的输出没有错误:

test=# INSERT INTO bati (id_bati,code_bati,code_parcelle,id_interne) VALUES (5,'CODEBATI001','CODEPARC001',02);
INSERT 0 1
test=# INSERT INTO bati (id_bati,code_bati,code_parcelle,id_interne) VALUES (6,'CODEBATI002','CODEPARC002',02);
INSERT 0 1
test=#  DELETE FROM bati;
DELETE 0

(抱歉我的英语是法语)

2 个答案:

答案 0 :(得分:2)

根据触发操作,应使用if-else分支返回NEWOLD。变量TG_OP具有文本类型&可以直接在插入查询中使用。

因此,函数定义变为:

CREATE FUNCTION archive_bati() 
    RETURNS TRIGGER AS $$
BEGIN
INSERT INTO bati_history (event,id_bati,code_bati,code_parcelle) 
VALUES (TG_OP, OLD.id_bati, OLD.code_bati, OLD.code_parcelle);
IF TG_OP = 'DELETE' 
    THEN RETURN OLD; 
    ELSE RETURN NEW;
END IF;
END;
$$ LANGUAGE PLPGSQL;

另外,对于我来说似乎没有必要在1满足时定义两个触发器:

CREATE TRIGGER bati_trigger_before_update BEFORE UPDATE OR DELETE
ON bati FOR EACH ROW
EXECUTE PROCEDURE archive_bati();

答案 1 :(得分:1)

删除行时,NEW为空。如果before触发器返回null,则意味着应取消该操作。然后,您应该返回OLD进行删除,并返回NEW进行更新。

来自doc

  

对于DELETE上的触发器,返回值不包含   直接效果,但必须为非null才能使触发操作   继续。请注意,DELETE触发器中的NEW为null,因此返回   通常是不明智的。 DELETE触发器中通常的习惯用法是   返回OLD。