数组错误将动态数量的参数传递给函数

Array error passing dynamic number of parameters to function

我正在尝试创建一个函数来接收我的模式中已创建的 table 的名称以及此 table 中的多个列名称(动态列数)和 return a table,所有列都在一个唯一的列中,每列的值用逗号分隔。

我正在尝试这个:

CREATE OR REPLACE PROCEDURE public.matching(IN table text, VARIADIC column_names text[])
    LANGUAGE 'plpgsql'

AS $BODY$DECLARE  
    column_text text;
BEGIN
EXECUTE format ($$ SELECT array_to_string(%s, ' ')$$, column_names) into column_text;

EXECUTE format ($$ CREATE TABLE temp1 AS
SELECT concat(%s, ' ') FROM %s $$, column_text, table);

END;$BODY$;

这return一个错误: 错误:«{» 处或附近的语法错误 第 1 行:SELECT array_to_string({city,address}, ' ')

哪个是错误的?

我提出不同但相似的代码。

使用以下脚本:

CREATE OR REPLACE PROCEDURE public.test(IN p_old_table text, IN p_old_column_names text[], IN p_new_table text)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE  
   old_column_list text;
   ctas_stmt text;
BEGIN
old_column_list = array_to_string(p_old_column_names,',');
RAISE NOTICE 'old_column_list=%', old_column_list; 
ctas_stmt = format('CREATE TABLE %s AS SELECT %s from %s', p_new_table, old_column_list, p_old_table); 
RAISE NOTICE 'ctas_stmt=%', ctas_stmt; 
EXECUTE ctas_stmt;
END;
$BODY$;
--
create table t(x int, y text, z timestamp, z1 text);
insert into t values (1, 'OK', current_timestamp, null);
select * from t;
--
call test('t',ARRAY['x','y','z'], 'tmp');
--
\d tmp;
select * from tmp;

我有以下执行:

CREATE OR REPLACE PROCEDURE public.test(IN p_old_table text, IN p_old_column_names text[], IN p_new_table text)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE  
   old_column_list text;
   ctas_stmt text;
BEGIN
old_column_list = array_to_string(p_old_column_names,',');
RAISE NOTICE 'old_column_list=%', old_column_list; 
ctas_stmt = format('CREATE TABLE %s AS SELECT %s from %s', p_new_table, old_column_list, p_old_table); 
RAISE NOTICE 'ctas_stmt=%', ctas_stmt; 
EXECUTE ctas_stmt;
END;
$BODY$;
CREATE PROCEDURE

create table t(x int, y text, z timestamp, z1 text);
CREATE TABLE

insert into t values (1, 'OK', current_timestamp, null);
INSERT 0 1

select * from t;
 x | y  |             z              | z1 
---+----+----------------------------+----
 1 | OK | 2020-04-14 11:37:28.641328 | 
(1 row)

call test('t',ARRAY['x','y','z'], 'tmp');
psql:tvar.sql:24: NOTICE:  old_column_list=x,y,z
psql:tvar.sql:24: NOTICE:  ctas_stmt=CREATE TABLE tmp AS SELECT x,y,z from t
CALL

                          Table "public.tmp"
 Column |            Type             | Collation | Nullable | Default 
--------+-----------------------------+-----------+----------+---------
 x      | integer                     |           |          | 
 y      | text                        |           |          | 
 z      | timestamp without time zone |           |          | 

select * from tmp;
 x | y  |             z              
---+----+----------------------------
 1 | OK | 2020-04-14 11:37:28.641328
(1 row)

如果您简化动态的生成 SQL,事情会变得更容易:

CREATE OR REPLACE PROCEDURE public.matching(IN table_name text, VARIADIC column_names text[])
    LANGUAGE plpgsql
AS 
$BODY$
DECLARE  
  l_sql text;
BEGIN
  l_sql := format($s$
                   create table temp1 as
                   select concat_ws(',', %s) as everything 
                   from %I
                  $s$, array_to_string(column_names, ','), table_name);
  raise notice 'Running %', l_sql;
  EXECUTE l_sql;
END;
$BODY$;

所以如果你传入 'some_table'{'one', 'two', 'three'} 生成的 SQL 将如下所示:

create table temp1 as select concat_ws(',', one,two,three) as everything from some_table

我还为新列使用了列别名,这样新的 table 就有了定义的名称。请注意,我将列名放入 SQL 字符串的方式无法正确处理需要双引号的标识符(但无论如何都应避免)


如果您想 "return a table",那么函数可能是更好的解决方案:

CREATE OR REPLACE function matching(IN table_name text, VARIADIC column_names text[])
  returns table (everything text)
  LANGUAGE plpgsql
AS 
$BODY$
DECLARE  
  l_sql text;
BEGIN
  l_sql := format($s$
                   select concat_ws(',', %s) as everything 
                   from %I
                  $s$, array_to_string(column_names, ','), table_name);
  return query execute l_sql;
END;
$BODY$;

那么你可以这样使用它:

select *
from matching('some_table', 'one', 'two', 'three');