Postgres使用INSTEAD OF触发器INSERT ON CONFLICT行为

时间:2017-06-13 18:21:24

标签: postgresql view triggers insert

假设我有以下表格和视图:

CREATE TABLE table_a(
    field_x INTEGER PRIMARY KEY,
    id SERIAL UNIQUE
);
CREATE TABLE table_b(
    a_id INTEGER PRIMARY KEY REFERENCES table_a(id),
    field_y INTEGER NOT NULL
);
CREATE VIEW v AS SELECT * FROM table_a JOIN table_b ON table_a.id=table_b.a_id;

我希望能够插入到视图中,因此我创建了以下函数并触发:

CREATE FUNCTION insert_into_view()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $function$
   DECLARE new_id INTEGER;
   BEGIN
      IF TG_OP = 'INSERT' THEN
        INSERT INTO table_a (field_x) VALUES (NEW.field_x) ON CONFLICT DO NOTHING RETURNING id INTO new_id;
        IF new_id IS NULL THEN
          SELECT id FROM table_a WHERE field_x=NEW.field_x INTO new_id;
        END IF;
        INSERT INTO table_b (a_id, field_y) VALUES (new_id, NEW.field_y);
      END IF;
      RETURN NEW;
    END;
$function$;
CREATE TRIGGER view_insert_trigger
    INSTEAD OF INSERT ON
      v FOR EACH ROW EXECUTE PROCEDURE insert_into_view();

现在我想只在视图中还没有field_x的行时才将值插入到视图中,例如:

INSERT INTO v (field_x, field_y) VALUES (5,6);
INSERT INTO v (field_x, field_y) VALUES (5,8) ON CONFLICT DO NOTHING;

我希望第二个插入无声地执行任何操作。但是,我明白了:

ERROR:  duplicate key value violates unique constraint "table_b_pkey"
DETAIL:  Key (a_id)=(2) already exists.
CONTEXT:  SQL statement "INSERT INTO table_b (a_id, field_y) VALUES (new_id, NEW.field_y)"

我知道为什么我收到此错误:函数insert_into_view在插入table_b时未指定ON CONFLICT行为,默认情况下查询失败。因此我的问题是:我可以将ON CONFLICT行为从视图插入到表插入中涟漪吗? (我可能希望稍后指定不同的冲突行为,所以如果我可以避免,我不想在触发器功能中对其进行硬编码。)

谢谢!

1 个答案:

答案 0 :(得分:0)

我仍然不确定如果我理解你的话。但我试试:

如果你改变了

INSERT INTO table_b (a_id, field_y) VALUES (new_id, NEW.field_y)

INSERT INTO table_b (a_id, field_y) VALUES (new_id, NEW.field_y) ON CONFLICT DO NOTHING

在功能中它将开始静默工作。

关于

INSERT INTO v (field_x, field_y) VALUES (5,8) ON CONFLICT DO NOTHING;

我认为您只能对具有唯一约束的表使用ON CONFLICT,因此,当您指定constraint_name的target_name

时,外部表和规则将忽略ON CONFLICT DO NOTHING并失败