使用存储过程插入列列表

Insert list of column with stored procedure

我有一个 Matlab 脚本,我想在其中使用存储过程而不是将所有指令发送到服务器。问题是我必须处理包含不同列的字符串变量,例如:

listColumns = '(column1, column2, column3, ... columnN)';

我想知道的是如何使用动态 SQL 创建一个存储过程,以将列列表作为字符串输入参数进行插入?是否可能或者我是否需要更改我的脚本以使其更容易?

这对我来说很新,我尝试了更简单的存储过程,我只需要一列并且效果很好,但我暂时坚持使用它:

CREATE OR REPLACE FUNCTION myfunction(
    tablename regclass, 
    listColumns regclass,
    listColumnsTarget regclass)
    RETURNS void
    LANGUAGE = 'plpgsql'
AS $$
BEGIN
    EXECUTE format('INSERT INTO ' %s %s '(SELECT ' %s ' FROM anotherTable)',
    tablename, listeColumns, listColumnsTarget);
END
$$;

我希望让存储过程正常工作,但它失败了,我收到语法错误...

regclass 类型只能包含某个数据库对象的一个​​标识(由 pg_class 系统 table 的一行描述)。您不能使用 regclass 类型来传递列名,因为只有列不是 table。 regclass 类型是特殊的并根据系统检查值 tables.

postgres=# select 'xxx'::regclass;
ERROR:  relation "xxx" does not exist
LINE 1: select 'xxx'::regclass;
               ^

Postgres 有特殊类型的 SQL 标识符 - name。如果你想传递更多的值,你应该使用一个名称数组 - name[]。但是对于来自外部的输入,最好使用通常的 text 类型并在函数内部处理必要的操作。在这种情况下,使用 name 类型对我们没有帮助。

需要什么?转义——这是针对语法错误或 SQL 注入的清理。例如 - 标识符:fubu, boo-boo, AA 应该被翻译成安全的标识符列表:fubi, "boo-boo", "AA"。这一步很重要

Postgres 没有这个 fork for list 的任何函数,但我们可以编写自己的函数:

CREATE OR REPLACE FUNCTION sanitize_identifiers(text)
RETURNS text AS $$
  SELECT string_agg(quote_ident(v), ',') 
    FROM unnest(string_to_array(, ',')) g(v)
$$ LANGUAGE sql;

现在,我们可以这样写函数:

CREATE OR REPLACE FUNCTION foo(tablename regclass,
                               columns text)
RETURNS void AS $$
BEGIN
  -- should to print valid SQL
  RAISE NOTICE '%',
    FORMAT('INSERT INTO %s SELECT %s FROM tab',
            tablename,
            sanitize_identifiers(columns));
END;
$$ LANGUAGE plpgsql;

结果:

postgres=# select foo('Test','a,b,c,C');
NOTICE:  INSERT INTO test SELECT a,b,c,"C" FROM tab