postgresql: использование NEW. * в динамической команде для EXECUTE - PullRequest
1 голос
/ 16 июля 2010

я пытаюсь создать триггер plpgsql для postgresql 8.3, который автоматически вставляет таблицу перед вставкой по столбцу 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

У меня есть 2 вопроса:

  1. Возможно ли вообще использовать NEW в EXECUTE или в утверждении есть какая-то ошибка?
  2. если это просто невозможно, кто-нибудь знает, как получить значения из NEW, чтобы я мог использовать их в выражении? единственное, что приходит мне в голову, - это использовать information_schema, чтобы получить имена столбцов для основной таблицы, а затем попытаться получить динамический доступ к значениям NEW - что я тоже не знаю, как: (

ТНХ

Ответы [ 2 ]

3 голосов
/ 23 июля 2013

Вы можете использовать

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

Я нашел это спрятанным в некоторых отдаленных районах: D. Я использую 9,1

0 голосов
/ 16 июля 2010

Эта настройка отлично работает здесь (версии 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');
...