0

I working in PostgreSQL past years, but i had no idea about array concept and how to handle array in PostgreSQL. i need a dynamic query for selecting columns in multiple table and the result will be in cursor, columns names should be dynamically will change.

for e.g (in a multiple table totally 30 columns is there If user need col1, col5,col6,col25), so select statement query will be dynamically will change like:

select col1, col5,col6,col25 from table ....

another user need col2,col5,col7,col29,col26, select statement will change dynamically as

select col2,col5,col7,col29,col26 from table .... and so on.

stored procedure passing parameters will be array

create or replace function func_my_method(check_in character varying, sel character varying[])...

this sel[] contains like

          sel[0]:='col1_name'
          sel[1]:='col5_name'
          sel[2]:='col6_name'
          sel[3]:='col25_name'

so first we have to split the array values in separate variable and these variable will be assumed in select statement will be

'select'||col1, col5,col6,col25||'from......'

Finally want to say briefly I need to pass an array in parameters and have to separate a array values and it will assign to separate variables. these variable will use to select a statement in dynamic manner

4
  • so you create your dynamic statement. what you do with it?.. return what? setof? table? number of rows? Commented Mar 23, 2017 at 9:15
  • @VaoTsun i doesn't create any statement or procedure for this i mentioned just for your reference. i need a procedure for this above criteria and will return as cursor. Kindly help me regarding this. Commented Mar 23, 2017 at 9:46
  • 1
    So, you need something like a refcursor? rextester.com/FMCUW60860 -- Although please don't forget to quote column names with either format() or quote_ident() to minimize SQL injection possibility. Commented Mar 23, 2017 at 9:54
  • @pozs Ya exactly! it will return refcursor Commented Mar 23, 2017 at 10:07

1 Answer 1

2

A bare refcursor can contain any number of columns. Although you'll need a special statement to read from it: FETCH ...

CREATE OR REPLACE FUNCTION func_my_method(check_in text, sel text[], ref refcursor)
  RETURNS refcursor
  LANGUAGE plpgsql
AS $func$
BEGIN
  OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg(quote_ident(c), ', ')
                                     FROM   unnest(sel) c) || ' FROM ...';
  RETURN ref;
END;
$func$;

SELECT func_my_method('check_in', ARRAY['col1', 'col2'], 'sample_name');
FETCH ALL IN sample_name;

http://rextester.com/ZCZT84224

Note: You could omit the refcursor parameter & DECLARE one in your function body. This way PostgreSQL will generate a (non-conflicting) name for the refcursor, which will be returned when calling SELECT func_my_method(...). You'll need that name in the FETCH ... statement.

Update: If you want to fully qualify (some) columns (i.e. write table name & column too), you'll need either:

CREATE OR REPLACE FUNCTION func_my_method2(check_in text, sel text[], ref refcursor)
  RETURNS refcursor
  LANGUAGE plpgsql
AS $func$
BEGIN
  OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg((SELECT string_agg(quote_ident(c), '.')
                                                        FROM   unnest(string_to_array(fq, '.')) c), ', ')
                                     FROM   unnest(sel) fq) || ' FROM ...';
  RETURN ref;
END;
$func$;

SELECT func_my_method2('check_in', ARRAY['col1', 'check_in.col2'], 'sample_name2');
FETCH ALL IN sample_name2;

(this will split the sel parameter into "parts" of the fully qualified name on . -- but have a disadvantage: the table & column names cannot contain .)

Or:

CREATE OR REPLACE FUNCTION func_my_method3(check_in text, sel text[][], ref refcursor)
  RETURNS refcursor
  LANGUAGE plpgsql
AS $func$
BEGIN
  OPEN ref FOR EXECUTE 'SELECT ' || (SELECT string_agg((SELECT string_agg(quote_ident(sel[i][j]), '.')
                                                        FROM   generate_subscripts(sel, 2) j), ', ')
                                     FROM   generate_subscripts(sel, 1) i) || ' FROM ...';
  RETURN ref;
END;
$func$;

SELECT func_my_method3('check_in', ARRAY[ARRAY['check_in', 'col1'], ARRAY['check_in', 'col2']], 'sample_name3');
FETCH ALL IN sample_name3;

(but this has an uncomfortable consequence: since arrays need to be rectangular, all column sub-arrays need to be the same exact dimensions; so you'll need to provide table name for all of the columns or to neither of them.)

http://rextester.com/JNI24740

Sign up to request clarification or add additional context in comments.

4 Comments

@dineshdanny yes, fully qualified names cannot be used directly with format() or quote_ident(). If you want to select from only 1 table, just omit them in the parameters & use 'SELECT mm_items.' || (SELECT string_agg(quote_ident(c), ', mm_items.') ... ...
@dineshdanny ... if you want to use multiple tables then you either don't use quotation in your function (but then always call that function from a trusted source; maybe REVOKE some privileges to achieve that) -- or, you'll need to "parse" the sel parameter. (f.ex. split on .).
@pozs Can you pls send me an example for this multiple table.
SELECT func_my_method('CDM', ARRAY['mm_items.id','mm_items.nm_code','um.code']);

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.