【问题标题】:postgresql: using NEW.* in dynamic command for EXECUTEpostgresql:在 EXECUTE 的动态命令中使用 NEW.*
【发布时间】:2013-07-23 15:30:18
【问题描述】:

我尝试为 postgresql 8.3 创建一个 plpgsql 触发器,它在插入之前自动对表进行分区 通过 id 列

如果目标表不存在,它将被创建,然后插入到那里

所以我用这样的新表名创建了插入语句

exec_insert := 'INSERT INTO '||TG_TABLE_SCHEMA||'.'||TG_RELNAME||'_'||destinationid||' VALUES('||NEW.*||')';
EXECUTE exec_insert;

导致错误:

ERROR:  NEW used in query that is not in a rule

我有两个问题:

  1. 甚至可以在 EXECUTE 中使用 NEW 还是语句中有错误?
  2. 如果这是不可能的,任何人都知道如何从 NEW 中获取值,以便我可以在语句中使用它们?我唯一想到的是使用 information_schema 来检索主表的列名,然后尝试动态访问 NEW 的值——我也不知道如何:(

谢谢

【问题讨论】:

    标签: postgresql inheritance triggers partitioning plpgsql


    【解决方案1】:

    你可以使用

    ...
    _sql varchar(100)= 'insert into some_table values ($1.*)';
    ...
    execute _sql using new;
    ...
    

    我发现它隐藏在一些偏远地区 :D 。我正在使用 9.1

    【讨论】:

    • 你拯救了我的一天。谢谢,这应该标记为正确答案。
    【解决方案2】:

    此设置在这里运行良好(8.4 和 9.0 版):

    CREATE TABLE customer
    (
      id bigserial NOT NULL,
      name text,
      datecreated timestamp with time zone DEFAULT now(),
      CONSTRAINT customer_pkey PRIMARY KEY (id) USING INDEX TABLESPACE pg_default
    );
    
    CREATE OR REPLACE FUNCTION test_trigger()
      RETURNS trigger AS
    $BODY$
    declare
        query   text;
    begin
        query := 'INSERT INTO customer_' || substring(NEW.name,1,1) || ' VALUES(' || NEW.id || ','''|| NEW.name||''')';
        EXECUTE query;
    
        RETURN NULL;
    
        EXCEPTION
            WHEN undefined_table THEN
                query := 'CREATE TABLE "customer_' || substring(NEW.name,1,1) || 
                '"( CONSTRAINT "customer_' || substring(NEW.name,1,1) ||'_name_check" CHECK (lower(substring(name, 1, 1)) = ''' || substring(NEW.name,1,1) || '''::text)
                ) INHERITS (customer); CREATE INDEX "i_customer_' || substring(NEW.name,1,1) ||'_name" ON customer_' || substring(NEW.name,1,1) ||' USING btree(name);';
                EXECUTE query;
    
                query := 'INSERT INTO customer_' || substring(NEW.name,1,1) || ' VALUES(' || NEW.id || ','''|| NEW.name||''')';
                EXECUTE query;
    
                query := 'ANALYZE "customer_' || substring(NEW.name,1,1) || '"';
                EXECUTE query;
    
                RETURN NULL;
    
    end;
    $BODY$
      LANGUAGE plpgsql VOLATILE STRICT
      COST 100;
    
    CREATE TRIGGER t_customer
      BEFORE INSERT OR UPDATE OR DELETE
      ON customer
      FOR EACH ROW
      EXECUTE PROCEDURE test_trigger();
    
    CREATE TABLE customer
    (
      id bigserial NOT NULL,
      name text,
      datecreated timestamp with time zone DEFAULT now(),
      CONSTRAINT customer_pkey PRIMARY KEY (id) USING INDEX TABLESPACE pg_default
    );
    
    CREATE OR REPLACE FUNCTION test_trigger()
      RETURNS trigger AS
    $BODY$
    declare
        query   text;
    begin
        query := 'INSERT INTO customer_' || substring(NEW.name,1,1) || ' VALUES(' || NEW.id || ','''|| NEW.name||''')';
        EXECUTE query;
    
        RETURN NULL;
    
        EXCEPTION
            WHEN undefined_table THEN
                query := 'CREATE TABLE "customer_' || substring(NEW.name,1,1) || 
                '"( CONSTRAINT "customer_' || substring(NEW.name,1,1) ||'_name_check" CHECK (lower(substring(name, 1, 1)) = ''' || substring(NEW.name,1,1) || '''::text)
                ) INHERITS (customer); CREATE INDEX "i_customer_' || substring(NEW.name,1,1) ||'_name" ON customer_' || substring(NEW.name,1,1) ||' USING btree(name);';
                EXECUTE query;
    
                query := 'INSERT INTO customer_' || substring(NEW.name,1,1) || ' VALUES(' || NEW.id || ','''|| NEW.name||''')';
                EXECUTE query;
    
                query := 'ANALYZE "customer_' || substring(NEW.name,1,1) || '"';
                EXECUTE query;
    
                RETURN NULL;
    
    end;
    $BODY$
      LANGUAGE plpgsql VOLATILE STRICT
      COST 100;
    
    CREATE TRIGGER t_customer
      BEFORE INSERT OR UPDATE OR DELETE
      ON customer
      FOR EACH ROW
      EXECUTE PROCEDURE test_trigger();
    
    INSERT INTO customer(name) VALUES ('john'), ('peter');
    

    【讨论】:

    • 同样的错误错误:新用于不在规则中的查询第 1 行:INSERT INTO set.test_123 VALUES (NEW.*)
    • ure 使用硬编码的列的名称,这也适用于此处,我尝试了一种更通用的方法,其中触发器可以在任何表上使用,而与列名/计数无关,这对于 plpgsql 目前似乎是不可能的如此处所述archives.postgresql.org/pgsql-sql/2004-06/msg00198.php
    • 在 plpgsql 中没有什么是不可能的,你只需要一点额外的创造力;)使用 pg_attribute 获取所有列和类型来创建新表,工作正常。
    猜你喜欢
    • 2018-06-24
    • 2019-03-29
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 2017-08-02
    • 2012-08-08
    • 2021-04-12
    • 1970-01-01
    相关资源
    最近更新 更多