如何在Postgresql中直接从触发器的过程代码中提取列?

fae0ux8s  于 2023-03-08  发布在  PostgreSQL
关注(0)|答案(1)|浏览(113)

当记录被更新或删除时,我有一些触发器可以用旧的列值更新表的相应历史表。这是一个触发器的例子,当主contact表被更新时,该触发器会更新contact_history表:

CREATE OR REPLACE FUNCTION public.contact_history_insert()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
          IF (TG_OP = 'DELETE') THEN
            INSERT INTO public.contact_history
              (dml_type, hard_deleted_on, first_name, last_name, middle_name)
            VALUES 
              ('D', now(), OLD.first_name OLD.last_name, OLD.middle_name)
            RETURN OLD;
          ELSEIF (TG_OP = 'UPDATE') THEN
            INSERT INTO public.contact_history
              (dml_type, first_name, last_name, middle_name)
            VALUES
              ('U', OLD.first_name OLD.last_name, OLD.middle_name);
            NEW.modified_on = now();
            RETURN NEW;
          END IF;
        END;

我正在尝试编写一个查询,它允许我从触发器的过程代码中提取列,现在,我意识到我可以使用以下查询查询表pg_attribute来获取触发器的信息:

SELECT  att_name
FROM pg_attribute
WHERE attrelid = (SELECT tgrelid FROM pg_trigger WHERE tgname = 'contact_history_trigger')
AND attnum > 0;

但是,这并没有给予我想要的结果。这给出了将要更新的列的结果,但不是触发器中编写的过程代码中使用的实际列的结果。例如,如果我在contact表中添加了一个新列,而没有更新contact触发器,它将自动更新pg_attribute中的attname。这与触发器代码中写入的实际列不相同。因此,我正在尝试编写一个查询,该查询将返回触发器代码中列出的列的结果。我意识到这可能包括使用正则表达式从INSERT INTO语句中提取数据,我还想将数据拆分为单个变量,并将它们放入新的数组变量中:

--Extract this data from the trigger code
(dml_type, hard_deleted_on, first_name, last_name, middle_name)
('D', now(), OLD.first_name, OLD.last_name, OLD.middle_namee)
(dml_type, first_name, last_name, middle_name)
('U', OLD.first_name OLD.last_name, OLD.middle_name)

---Expected output
vars_1 = [first_name, last_name, middle_name]
vars_2 = [OLD.first_name, OLD.last_name, OLD.middle_name] -- It would be a plus if it didn't extract the 'OLD' prefix
vars_3 = [first_name, last_name, middle_name]
vars_4 = [OLD.first_name, OLD.last_name, OLD.middle_name]

这看起来确实过于复杂,但我还没有找到一种更简单的方法,只需调用系统表(如pg_attributeinformation_schema.triggers)来检索数据,而不会出现我正在寻找的错误信息。
我知道这个查询返回触发器的实际过程代码:

SELECT prosrc FROM pg_proc WHERE proname = 'contact_history_insert';
gab6jxml

gab6jxml1#

如果表中的列顺序相同,并且历史记录表中的附加字段仅位于表的末尾,则可以按如下方式编写查询。

CREATE TABLE contact (
    first_name varchar NULL,
    last_name varchar NULL,
    middle_name varchar NULL
);

CREATE TABLE contact_history (
    first_name varchar NULL,
    last_name varchar NULL,
    middle_name varchar NULL,
    hard_deleted_on timestamp NULL
);

CREATE OR REPLACE FUNCTION test2.contact_history_insert()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
    INSERT INTO contact_history
    select new.*, now();
    RETURN NEW;
END;
$function$
;

create trigger contact_insert_trigger 
after insert
    on
    test2.contact for each row execute function test2.contact_history_insert();

第二种方法是在触发器中使用动态查询,可以使用information_schema获取表列名

相关问题