使用触发器更新新创建的行值

时间:2017-08-03 10:21:53

标签: postgresql triggers sql-update

我的问题如下:我在postgresql数据库中插入或更新一行,需要修改此行中的一个字段。但是,当我插入新行以在其他表格上SELECT JOIN时,我需要知道新的序列号PK。

我现在陷入困境,因为我已经完成AFTER INSERT AND UPDATE触发器以获得新的PK(kkw_block_id)。我使用SELECT得到了我需要的值,但之后我无法修改行中的值:使用AFTER INSERT AND UPDATE修改NEW.value并且如果我执行UPDATE在行上,我进入一个无限循环,触发器在触发器中调用...

CREATE TRIGGER tsvectorupdate
  AFTER INSERT OR UPDATE
  ON kkw_block
  FOR EACH ROW
  EXECUTE PROCEDURE kkw_search_trigger();

CREATE OR REPLACE FUNCTION kkw_search_trigger()
  RETURNS trigger AS
$BODY$

DECLARE vector_en TEXT;
  DECLARE vector_fr TEXT;
  DECLARE vector_de TEXT;
    BEGIN   
        -- I need the new serial PK(kkw_id) in the following section.
        SELECT coalesce(modell_en, '') || ', ' || coalesce(bezeichnung_en,'') || ', ' || coalesce(kkw.kkw_name_en,'') || ', ' || coalesce(kkw_typ.typ_abr,'') || ', ' || coalesce(kkw_typ.typ_desc_en,'') || ', ' || coalesce(kkw_typ.typ_desc_short_en,'') INTO vector_en
        FROM kkw_block
        LEFT JOIN kkw ON NEW.kkw_id = kkw.kkw_id
        LEFT JOIN kkw_typ ON NEW.kkw_typ_id = kkw_typ.kkw_typ_id
        WHERE kkw_block_id = NEW.kkw_block_id;

        -- I need to update a field of the newly created or updated row. 
        NEW.search_vector_en := to_tsvector('english', 'new test vector'); --- This doesn't work with 'AFTER UPDATE' trigger.

        RETURN NULL;
    END
$BODY$

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

删除PK的默认值并将其分配到 BEFORE 触发器中。您必须将现有的触发器从AFTER更改为BEFORE。

您可以从序列中分配PK:

NEW.kkw_block_id = nextval('your_sequence_name_here');

由于您对INSERT和DELETE都使用相同的函数,因此需要检查它是否为INSERT,然后才使用序列。我还检查了PK是否为空。我认为单独就足以在更新期间不会覆盖它。

IF (TG_OP = 'INSERT') AND NEW.kkw_block_id IS NULL THEN
  NEW.kkw_block_id = nextval('your_sequence_name_here');
END IF;

只要此触发器适用于每个新行,这将是正常的,似乎是这种情况。这将允许您修改NEW,它将反映在表格中保存的数据中。

答案 1 :(得分:0)

我最终得到了以下解决方案。我做了一个BEFORE触发器。问题是LEFT JOIN引用了尚未存在新行的表。这不是理想的,但在这里:

CREATE TRIGGER tsvectorupdate
  BEFORE INSERT OR UPDATE
  ON kkw_block
  FOR EACH ROW
  EXECUTE PROCEDURE kkw_search_trigger();

CREATE TYPE kkw_type_record_type AS (typ_abr TEXT, typ_desc_en TEXT, typ_desc_short_en TEXT);
CREATE TYPE kkw_record_type AS (kkw_name_en TEXT);

CREATE OR REPLACE FUNCTION kkw_search_trigger()
  RETURNS trigger AS
$BODY$

  DECLARE kkw_rec kkw_record_type;
  DECLARE kkw_typ_rec kkw_type_record_type;

  DECLARE vector_en TEXT;

    BEGIN   
        --- make a individual select instead of LEFT JOIN
        SELECT kkw_name_en  INTO kkw_rec.kkw_name_en
        FROM kkw
        WHERE kkw.kkw_id = NEW.kkw_id;

        --- make a individual select instead of LEFT JOIN
        SELECT typ_abr, typ_desc_en, typ_desc_short_en INTO kkw_typ_rec.typ_abr, kkw_typ_rec.typ_desc_en, kkw_typ_rec.typ_desc_short_en
        FROM kkw_typ
        WHERE kkw_typ.kkw_typ_id = NEW.kkw_typ_id;

        vector_en := coalesce(NEW.modell_en, '') || ', ' || coalesce(NEW.bezeichnung_en,'') || ', ' || coalesce(kkw_rec.kkw_name_en,'') || ', ' || coalesce(kkw_typ_rec.typ_abr,'') || ', ' || coalesce(kkw_typ_rec.typ_desc_en,'') || ', ' || coalesce(kkw_typ_rec.typ_desc_short_en,'');

        NEW.search_vector_en := to_tsvector('english', vector_en);          
        RETURN NEW;
    END
$BODY$