Postgresql 将动态参数数传递给函数时发生数组错误
我正在尝试创建一个函数,以接收已创建模式中的表名和该表中的多个列名(动态列数),并返回一个表,其中所有列都位于一个唯一列中,每个列的值用逗号分隔 我正在尝试这个:Postgresql 将动态参数数传递给函数时发生数组错误,postgresql,stored-procedures,plpgsql,dynamic-sql,Postgresql,Stored Procedures,Plpgsql,Dynamic Sql,我正在尝试创建一个函数,以接收已创建模式中的表名和该表中的多个列名(动态列数),并返回一个表,其中所有列都位于一个唯一列中,每个列的值用逗号分隔 我正在尝试这个: CREATE OR REPLACE PROCEDURE public.matching(IN table text, VARIADIC column_names text[]) LANGUAGE 'plpgsql' AS $BODY$DECLARE column_text text; BEGIN EXECUTE
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$;
这将返回一个错误:
错误:«{»处或附近的语法错误
第1行:选择数组到字符串({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
select *
from matching('some_table', 'one', 'two', 'three');
我还为新列使用了列别名,以便新表具有已定义的名称。请注意,我将列名放入SQL字符串的方式无法正确处理需要双引号的标识符(但无论如何都应避免使用双引号)
如果要“返回表”,则函数可能是更好的解决方案:
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$;
然后你可以这样使用它:
create table temp1 as select concat_ws(',', one,two,three) as everything from some_table
select *
from matching('some_table', 'one', 'two', 'three');
谢谢你的问题!!但是,使用这个脚本,我的问题没有得到解决,不是吗?我的目标是创建一个具有唯一列的表。该列的值是我作为参数在函数中传递的所有列的值,用逗号分隔。我对我的问题做了一些更改,可能不清楚。抱歉。