在 Postgres 中创建一个触发器,将记录插入到另一个添加了列的表中

5 postgresql triggers

我在 postgres 中创建了这两个表,

CREATE TABLE EMPLOYEE(
   ID           INT             PRIMARY KEY NOT NULL,
   NAME         VARCHAR(100)    NOT NULL,
   ADDRESS      VARCHAR (250)   NOT NULL
);


CREATE TABLE HIST_EMPLOYEE(
   HISTORYNUM   INT             NOT NULL,
   ID           INT             NOT NULL,
   NAME         VARCHAR(100)    NOT NULL,
   ADDRESS      VARCHAR (250)   NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

..所以每当我想插入、更新或删除EMPLOYEE表中的记录时,该记录都应该插入HIST_EMPLOYEE表中。无论是单行还是多行

..我知道这个网站上有很多答案..但问题是我在我的历史表中添加了一列HIST_EMPLOYEE..这就是为什么我不能使用大多数答案发布的这个脚本,

insert into hist_employee select * from employee
Run Code Online (Sandbox Code Playgroud)

...这是我到目前为止所开始的,但它有很多错误..

扳机

CREATE TRIGGER insertHistory
    AFTER INSERT OR UPDATE ON employee   --MAIN TABLE
        EXECUTE PROCEDURE insertHistory('hist_employee');  --HISTORY TABLE
Run Code Online (Sandbox Code Playgroud)

触发功能

CREATE OR REPLACE FUNCTION insertHistory() RETURNS TRIGGER AS 
$func$
    BEGIN
       EXECUTE format('insert into %I select * from %I', TG_ARGV[0] ,TG_TABLE_NAME );
       return null;
    END;
$func$ 
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 该触发器也应该适用或足够灵活,可以在具有不同列集的其他表上实现。
  2. HISTORYNUM 列每个 id 都是唯一的,

  3. 并且,是否可以将这 3 个(插入后、更新后、删除前)合并到一个触发器中?

感谢所有回复的人...如果您发现我的问题太模糊,我很抱歉

kli*_*lin 5

我认为该列historynum使用起来太麻烦。我建议用时间戳替换它。您还可以添加指示操作类型的列。

create table employee (
    id int primary key,
    name text not null,
    address text not null);

create table employee_history (
    id int,
    name text not null,
    address text not null,
    modified_at timestamp,
    operation text);
Run Code Online (Sandbox Code Playgroud)

您必须先使用触发器才能访问当前修改/删除的行。

create or replace function trigger_on_employee()
returns trigger language plpgsql
as $function$
begin
    if tg_op = 'DELETE' then
        insert into employee_history
        select old.*, current_timestamp, tg_op;
        return old;
    else
        insert into employee_history
        select new.*, current_timestamp, tg_op;
        return new;
    end if;
end; $function$;

create trigger trigger_on_employee
  before insert or update or delete
  on employee
  for each row
  execute procedure trigger_on_employee();
Run Code Online (Sandbox Code Playgroud)

一些测试:

insert into employee values 
(1, 'John', 'Berlin'),
(2, 'Adam', 'Paris'),
(3, 'Mike', 'London');

update employee
set name = 'Anna'
where id = 1;

delete from employee
where id = 2;

select * 
from employee_history
order by modified_at;

 id | name | address |        modified_at         | operation 
----+------+---------+----------------------------+-----------
  1 | John | Berlin  | 2015-12-20 16:26:35.703232 | INSERT
  2 | Adam | Paris   | 2015-12-20 16:26:35.703232 | INSERT
  3 | Mike | London  | 2015-12-20 16:26:35.703232 | INSERT
  1 | Anna | Berlin  | 2015-12-20 16:26:35.750609 | UPDATE
  2 | Adam | Paris   | 2015-12-20 16:26:35.761521 | DELETE
(5 rows)
Run Code Online (Sandbox Code Playgroud)


Dar*_*rax 0

  1. 恕我直言,过度概括你的触发函数确实没有任何好处,尤其是像这个这样短的函数。保持简单,为每个历史表编写一个新的触发器函数。
  2. HISTORYNUM柱子?没关系; 我看到了。但不知道该怎么办。
  3. 不可以。单个触发器必须是 BEFORE AFTER不过,您可以声明多个调用同一函数的触发器。

这样一来,您所编写的触发器函数几乎肯定会遇到“变异表”错误。此外,每次发生更新时,您似乎都试图将“当前”表的全部内容复制到“历史”表中。您已经在伪记录和中分别拥有新数据( for和)和旧数据( for和) 。为什么不利用它呢?INSERTUPDATEUPDATEDELETENEWOLD

除此之外,你说你有

这么多错误..

也许如果您告诉我们其中一些问题,我们可以帮助您解决这些问题。