如何在触发器函数

时间:2018-04-25 13:05:45

标签: postgresql

我有一个插入触发器函数,其中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érateurn'existepas:record ~~ unknown       第1行:SELECT old_table LIKE'%ens%'                                ^       提示:Aucunopérateurne对应aunomdonnéetaux types d'arguments。       Vous devez ajouter des conversions explicites de type。       QUERY:SELECT old_table LIKE'%ens%'       背景信息:功能PL / pgsql validation_sio.afi_validation_sio(),ligne 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 :(得分:0)

在SQL语句中不能有EXECUTE,它是PL / pgSQL语句。

遍历表格并为每个表格发出一个EXECUTE

请注意,您不能将模式或表名作为USING的参数,因为这些名称需要在分析时知道。

使用format函数构造动态语句,以避免恶意创建具有奇怪名称的表的用户进行SQL注入。

答案 1 :(得分:0)

我已经重新格式化了你的触发功能并改变了一些事情,看看是否有效。

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更改为我认为您真正希望它执行的操作。您希望它将表的内容复制到新表中,对吧?这样就可以了。