INSERT和RETURNING与NULL返回触发器

时间:2014-05-20 09:47:46

标签: sql database postgresql plpgsql

为了便于阅读,我将提供数据库的简化版本。

假设我有一个基表:

CREATE TABLE base_table
(
  id bigserial NOT NULL,
  name text,
  CONSTRAINT requests_pkey PRIMARY KEY (id)
);

继承它的人:

CREATE TABLE child_table
()
INHERITS (base_table);

在基表上设置了一个触发器:

CREATE OR REPLACE FUNCTION insert_row()
  RETURNS trigger AS
$BODY$
BEGIN
    INSERT INTO child_table VALUES (NEW.*);
    RETURN NULL;
END;
$BODY$
  LANGUAGE plpgsql;

CREATE TRIGGER row_insert_trigger
  BEFORE INSERT
  ON base_table
  FOR EACH ROW
  EXECUTE PROCEDURE insert_row();

我的数据库中此类触发器的目的是根据某些规则对基表进行分区。它按预期工作,但它有一个显着的缺点。这样INSERT

INSERT INTO base_table (name) VALUES ('test') RETURNING id

将插入一行,但由于触发器函数返回NULL,它不会返回任何内容。我尝试了几个解决这个问题的方法,但是,坦率地说,我对它们都不满意:

  1. 使用规则而不是触发器。
  2. 上述问题的解决方案可能是一个简单的规则,例如:

    CREATE OR REPLACE RULE row_insert_rule AS
      ON INSERT TO base_table DO INSTEAD
      INSERT INTO child_table VALUES (NEW.*)
      RETURNING id;
    

    然而,在现实生活中,我想执行比这个简单插入更多的操作,这需要使用存储过程。我不知道如何在返回的规则中使用它:

    CREATE OR REPLACE RULE row_insert_rule AS
      ON INSERT TO base_table DO INSTEAD
      SELECT id FROM some_procedure(NEW)
      RETURNING id;
    

    显然会失败,因为使用SELECTRETURNING是无效的pgsql语法。在规则中省略RETURNING会导致INSERTs RETURNING失败。

    1. 两个触发器 - BEFOREAFTER
    2. 在此解决方案中,BEFORE触发器看起来与之前提供的触发器类似,但它不会返回NULL而是NEW - 因此它可以与RETURNING一起使用,但它会插入一行到base_table。之后可以使用AFTER触发器删除该行。我认为这个解决方案不够优雅 - 它看起来很奇怪,会导致id上的序列出现问题等等。

      1. 完全忽略INSERT
      2. 我可以执行一个存储过程,而不是在INSERT上使用base_table语句,该存储过程将在相应的表中插入一行。在我看来,这个解决方案在性能方面是最好的,但它需要使用这个数据库的应用程序“记住”不要在这个表上使用INSERT并依赖提供的存储过程 - 这是我能要求的因为我们系统的架构而无法实现。

        1. 在同一事务中选择id序列的当前值。
        2. 与上一个解决方案中的问题相同 - 要求应用程序执行的操作不仅仅是向表中插入数据。

          是否有一个简单,优雅,最重要的 - 快速(在性能方面)解决我的问题?或者 - 可以修改我的解决方案1号以正确使用RETURNING吗?

0 个答案:

没有答案