0

I'm trying to create a function to receive the name of the table in my schema already created and a several name of columns within this table (dynamic number of columns) and return a table with all the columns in a unique column with the value of each column separated by comma.

I'm trying this:

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$;

This return an error: ERROR: syntax error at or near «{» LINE 1: SELECT array_to_string({city,address}, ' ')

which is the error?

0

2 Answers 2

1

If you simplify the generation of the dynamic SQL, things get easier:

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$;

So if you e.g. pass in 'some_table' and {'one', 'two', 'three'} the generated SQL will look like this:

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

I also used a column alias for the new column, so that the new table has a defined name. Note that the way I put the column names into the SQL string won't properly deal with identifiers that need double quotes (but they should be avoided anyway)


If you want to "return a table", then maybe a function might be the better solution:

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$;

Then you can use it like this:

select *
from matching('some_table', 'one', 'two', 'three');
Sign up to request clarification or add additional context in comments.

Comments

0

I propose different but similar code.

With following script:

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;

I have following execution:

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)

1 Comment

Thanks for your question!! But, with this script, my problem is not solved, no? My objective is to create a table with one unique column. The value of that column is all the values of the columns that I pass as a parameter in the function, separated by a comma. I've changed my question a bit, maybe it wasn't clear. Sorry for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.