Postgres dynamic sql and list result - postgresql

I used EXECUTE(for dynamic sql) and SETOF(result is returning as list), but it is the wrong :(
create table test as
select 1 id, 'safd' data1,'sagd' data2
union
select 2 id, 'hdfg' data1,'sdsf' data2;
create or replace function test2(a varchar) returns SETOF record as
$BODY$
declare x record;
begin
for x in execute a loop
RETURN NEXT x;
end loop;
return;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
select * from test2('select * from test');

You will have to know in advance the structure of the returned record
select * from test2('select * from test') s(a int, b text, c text);
a | b | c
---+------+------
1 | safd | sagd
2 | hdfg | sdsf
Or if the returned set will always be a set of the test table then use the Akash's proposed solution.

replace
create or replace function test2(a varchar) returns SETOF RECORD as
with
create or replace function test2(a varchar) returns SETOF test as
^^^^ name of table (it specifies the datatypes of the set)

You need to add some OUT params.
CREATE FUNCTION test2(a character varying, OUT id integer, OUT data1 text, OUT data2 text) RETURNS SETOF record
LANGUAGE plpgsql
AS $$
begin
RETURN QUERY EXECUTE a;
end;
$$;

Related

Avoid 'ambiguous column' in simple PostgreSQL function returning table

Suppose I have the following table, function and execution:
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select a,b from mytable;
end;
$body$
language plpgsql STABLE;
select * from test(1);
I get an 'ambiguous column name' error. I can get rid of it by changing the selection to "select t.a, t.b from mytable t" (per some similar-ish posts). But it seems very odd to have to qualify the column names when there is only 1 table in my query. I'm porting code that has quite a lot of stored procedures selecting from single tables (in various ways) and returning a table with columns that have the same name. Is there a better way than this of avoiding the error, and still having an output table with the same column names?
Thanks for any leads.
you can (you should) to use aliases.
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select mt.a, mt.b from mytable mt;
end;
$body$
language plpgsql STABLE;
select * from test(1);
maybe thats an option, using format and query execute:
( as the error says, it doesnt know which a to take, the pl/pgSQL variable or a columname )
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
declare
lsQueryExecute text;
begin
lsQueryExecute = format('select a,b from mytable');
return query execute lsQueryExecute;
end;
$body$
language plpgsql STABLE;

How to get entire table data or multiple rows returned from a function in PG/PLSQL with pgAdmin 4.2.?

I tried using setof and table. While creating function in pgAdmin 4.2 there is no return type called setof or table. If I create function with setof and table name as a selected return type, it only returns one row of table.
CREATE FUNCTION pgsql_returnrecords() RETURNS SETOF RECORD(name char, city, char, id integer) AS
$BODY$
DECLARE
rec RECORD;
BEGIN
select name,city,id INTO rec from test;
return next rec;
END;
$BODY$ language plpgsql;
I want my function to return table data with all rows and columns.
It's either returns setof record or returns table(....) or setof table_name With returns setof record you have to specify the column names when using the function.
You are also not returning a complete result, because you only fetch a single row, put it into the record and return that. To return a real "set" you need to use return query in PL/pgSQL. But such a function is much better written as a SQL function:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
select name,city,id
from test;
$BODY$
language sql;
If you want to always return a complete row from the table test you can simplify that using returns setof test instead of returns table(..)
CREATE FUNCTION pgsql_returnrecords()
RETURNS setof test
AS
$BODY$
select *
from test;
$BODY$ language sql;
Or, if you insist on PL/pgSQL:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
BEGIN
return query
select name,city,id
from test;
END;
$BODY$
language plpgsql;
In both cases you have to use the function like a table in the FROM clause:
select *
from pgsql_returnrecords() ;

Select statement within function blank results

I'm using Postgresql and trying to have a select statement in a function to call out. At the moment the call gives me zero results
CREATE OR REPLACE FUNCTION f_all_male_borrowers
(
OUT p_given_names varchar(60),
OUT p_family_name varchar(60),
OUT p_gender_code integer
)
RETURNS SETOF record as $body$
declare body text;
BEGIN
SELECT into p_given_names,p_family_name, p_gender_code
borrower.given_names, borrower.family_name, gender.gender_code
FROM BORROWER
INNER join gender on borrower.gender_code=gender.gender_code
WHERE borrower.gender_code = '1';
RETURN ;
END;
$body$ LANGUAGE plpgsql;
Call to function:
select * from f_all_male_borrowers()
What is missing, or what am I doing wrong here?
Thank you
CREATE OR REPLACE FUNCTION f_all_male_borrowers
(
OUT p_given_names varchar(60),
OUT p_family_name varchar(60),
OUT p_gender_code integer
)
RETURNS SETOF record as
$body$
SELECT into p_given_names,p_family_name, p_gender_code
borrower.given_names, borrower.family_name, gender.gender_code
FROM BORROWER
INNER join gender on borrower.gender_code=gender.gender_code
WHERE borrower.gender_code = '1';
$body$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION f_all_male_borrowers()
OWNER TO postgres;
Try this and then call :
select * from f_all_male_borrowers();
Before doing that you need to check whether your query have result or not !!
After creating function then:
Got to Functions->Right click your function(ie,f_all_male_borrowers())-> Scripts->Select Script ->Then run it.
If it returns result then your procedure is correct.

Greenplum/Postgres 8 function dynamic result set?

I need to write a function that returns a table with unknown number of columns.
If i receive 'None' in column input parameter then that column shouldn't be included in the output. In postgres 9+ there is a solution for this problem.
something like below:
CREATE OR REPLACE FUNCTION data_of(id integer,col1 varchar,col2 varchar, col3 varchar)
RETURNS TABLE (count_rec, dimensions text[] ) AS
$func$
DECLARE
_dimensions text := 'col1, col2, col3'; -- If i receive 'None' in input param then i exclude that from column list
BEGIN
RETURN QUERY EXECUTE format('
SELECT count(*) as count_rec,
string_to_array($1) -- AS dimensions
FROM x
WHERE id = $2'
, _dimensions)
USING _dimensions , _id;
END
$func$ LANGUAGE plpgsql;
But in Greenplum (Postgres 8.2) i could not find any. Is there any similar solution?
thanks
You have 2 options to do it: use set-returning function returning "record" or returning your custom type.
First option:
create table test (a int, b int, c int, d varchar, e varchar, f varchar);
insert into test select id, id*2, id*3, (id*4)::varchar, (id*4)::varchar, (id*4)::varchar from generate_series(1,10) id;
create or replace function test_func(column_list varchar[]) returns setof record as $BODY$
declare
r record;
begin
for r in execute 'select ' || array_to_string(column_list, ',') || ' from test' loop
return next r;
end loop;
return;
end;
$BODY$
language plpgsql
volatile;
select * from test_func(array['a','c','e']) as f(a int, c int, e varchar);
Second option:
create table test (a int, b int, c int, d varchar, e varchar, f varchar);
insert into test select id, id*2, id*3, (id*4)::varchar, (id*4)::varchar, (id*4)::varchar from generate_series(1,10) id;
create type testtype as (
a int,
c int,
e varchar
);
create or replace function test_func() returns setof testtype as $BODY$
declare
r testtype;
begin
for r in execute 'select a,c,e from test' loop
return next r;
end loop;
return;
end;
$BODY$
language plpgsql
volatile;
select * from test_func();
But I'm 99% sure you're trying to do something wrong. In Greenplum the result of function execution cannot be used as a "table" in join conditions, because the function executes on the master. You even won't be able to create a table out of the last query returning the data from your function because of this limitation
In short, this is not a recommended way to work with data in Greenplum

RETURN cannot have a parameter in function returning set; use RETURN NEXT at or near "QUERY" Postgres

When I try to compile this function:
CREATE OR REPLACE FUNCTION test_proc4(sr_num bigint)
RETURNS TABLE(sr_number bigint, product_serial_number varchar(35))
AS $$
BEGIN
RETURN QUERY SELECT select sr_number,product_serial_number from temp_table where sr_number=sr_num
END;
$$
LANGUAGE 'plpgsql' VOLATILE;
Why do I get this error?
RETURN cannot have a parameter in function returning set; use RETURN NEXT at or near "QUERY"
I am using postgres version 8.4.
Aside from a typo (you duplicated select, and you didn't terminate the RETURN statement with a semicolon), I think you were quite close - just needed to disambiguate the table columns within the query by qualifying them with the table name. Try this (reformatted hopefully to improve readability):
CREATE OR REPLACE FUNCTION test_proc4(sr_num bigint)
RETURNS TABLE(sr_number bigint, product_serial_number varchar(35)) AS $$
BEGIN
RETURN QUERY
SELECT
temp_table.sr_number, temp_table.product_serial_number
from temp_table
where temp_table.sr_number=sr_num;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
Caveat: I only tested this in PG 9.4, so haven't tested it in your version yet (which is no longer supported, I might add). In case there are issues regarding PLPGSQL implementation between your version and 9.4, you can try this form as an alternative:
CREATE OR REPLACE FUNCTION test_proc4(sr_num bigint)
RETURNS TABLE(sr_number bigint, product_serial_number varchar(35)) AS $$
BEGIN
FOR sr_number, product_serial_number IN
SELECT
temp_table.sr_number, temp_table.product_serial_number
from temp_table
where temp_table.sr_number=sr_num
LOOP
RETURN NEXT;
END LOOP;
RETURN;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
A small sanity check using a table I populated with dummy data:
postgres=# select * from temp_table;
sr_number | product_serial_number
-----------+-----------------------
1 | product 1
2 | product 2
2 | another product 2
(3 rows)
postgres=# select * from test_proc4(1);
sr_number | product_serial_number
-----------+-----------------------
1 | product 1
(1 row)
postgres=# select * from test_proc4(2);
sr_number | product_serial_number
-----------+-----------------------
2 | product 2
2 | another product 2
(2 rows)