Как динамически копировать таблицы из информационной схемы внутри функции триггера - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть триггерная функция вставки, в которой NEW.schema_name ссылается на схему. Я хочу динамически копировать таблицы, найденные внутри этой схемы ('foobaz', 'barbaz'), как 'foo' и 'bar'. Затем я могу выполнять запросы без динамического sql.

Как я могу создать функцию или просто скопировать / вставить один и тот же блок кода для достижения этой цели.

РЕДАКТИРОВАТЬ:

Я не могу заставить этот динамический запрос работать. Часть внутри оператора WITH работает. Не нижняя часть «выполнить». Я не знаю, является ли это синтаксической проблемой, или плохим приведением, или какими-либо ограничениями в pgsql, которые делают его не работающим.

WITH info_schema_subset_table as (SELECT table_schema, table_name, 
     array_to_string((regexp_split_to_array(table_name,'_'))[4:array_length(regexp_split_to_array(table_name,'_'),1)-1] as new_table
     FROM information_schema.tables
     where table_schema = "schema_searched"
     ORDER BY new_table ASC)

  EXECUTE 'CREATE TABLE $2 as (SELECT * FROM $1)'
  USING info_schema_subset_table.table_schema || '.' ||info_schema_subset_table.table_name,info_schema_subset_table.new_table;

РЕДАКТИРОВАТЬ 2

... Сломанный код удален ...

В приведенном ниже коде, в котором я не уверен, правильный ли синтаксис, я получаю следующее от триггера

Ошибки провайдера: Ошибка PostGIS при добавлении функций: ERREUR: l'opérateur n'existe pas: запись ~~ неизвестна ЛИНИЯ 1: ВЫБРАТЬ old_table LIKE "% ens%" ^ ПОДСКАЗКА: Aucun opérateur не соответствует типу аргументов. Vous devez ajouter des преобразований объясняет тип. QUERY: ВЫБЕРИТЕ old_table LIKE "% ens%" КОНТЕКСТ: функция PL / pgsql validation_sio.afi_validation_sio (), строка 18 à CASE

РЕДАКТИРОВАТЬ 3:

CREATE OR REPLACE FUNCTION foo.foo()
RETURNS TRIGGER AS
$BODY$

DECLARE 
old_table record;
new_table record;
dynamic_query text;

BEGIN

IF TG_OP = 'INSERT'
THEN

FOR old_table IN SELECT table_schema|| '.' ||table_name
FROM information_schema.tables
where table_schema = NEW.nom_schema
LOOP

CASE 
 WHEN
  old_table LIKE '%ens%' THEN
  new_table := concat('SIT_',array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
 ELSE 
  new_table := concat('SID_',array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
END CASE;

dynamic_query := format('SELECT * FROM' || old_table ||);
EXECUTE dynamic_query
INTO new_table;

END LOOP;

RETURN NEW;

END IF;
END; 
$BODY$

LANGUAGE plpgsql VOLATILE;


CREATE TRIGGER foo
AFTER INSERT ON validation.validationfoo
FOR EACH ROW EXECUTE PROCEDURE foo.foo();

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Я немного переформатировал вашу функцию триггера и изменил несколько вещей, посмотрите, работает ли она.

CREATE OR REPLACE FUNCTION foo.foo()
    RETURNS TRIGGER AS
$BODY$
DECLARE 
    old_table record;
    new_table record;
    dynamic_query text;
BEGIN
    IF TG_OP = 'INSERT' THEN
        FOR old_table IN
            SELECT table_schema || '.' || table_name AS old_table_name
            FROM information_schema.tables
            WHERE table_schema = NEW.nom_schema
        LOOP
            new_table := concat(CASE WHEN old_table.old_table_name LIKE '%ens%' THEN 'SIT_' ELSE 'SID_' END,array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
            dynamic_query := 'CREATE TABLE ' || new_table || ' AS SELECT * FROM ' || old_table.old_table_name;
            EXECUTE dynamic_query;
        END LOOP;

        RETURN NEW;
    END IF;
END; 
$BODY$
LANGUAGE plpgsql VOLATILE;

Итак, основные вещи:

  • old_table - это запись, поэтому сравнение ее со строкой с LIKE не удалось. Вам нужно использовать имя поля. Поэтому я дал вашему полю имя и использовал его в сравнении LIKE.
  • Изменено присваивание new_table, чтобы оператор CASE помещался только в один изменяемый элемент, чтобы сделать различие более очевидным, а код - более кратким. Имейте в виду, я не знаю, действительно ли остальная часть этой строки верна, я просто оставил ее как есть.
  • Изменено создание dynamic_query. Как я сказал в комментарии, функция format использовалась неправильно, поэтому я просто использовал стандартную конкатенацию строк.
  • Изменен dynamic_query SQL на то, что, я думаю, вы действительно хотите, чтобы он делал. Вы хотите скопировать содержимое таблицы в новую таблицу, верно? Так что это сделает.
0 голосов
/ 25 апреля 2018

Вы не можете иметь EXECUTE внутри оператора SQL, это оператор PL / pgSQL.

Прокрутите таблицы и введите по одному EXECUTE для каждого.

Помните, что вы не можете иметь имя схемы или таблицы в качестве параметра с USING, потому что эти имена должны быть известны во время разбора.

Используйте функцию format для создания динамического оператора, чтобы вы могли избежать внедрения SQL пользователями, которые злонамеренно создают таблицы со странными именами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...