How do I execute a SELECT query in a text string? - sql

I have a function my_funct(param1,param2) returning a SELECT QUERY as a text, I usually C/c the result, remove quotes, then run it.
How can execute the returned text in a query that call the function ?
I expect something like this:
SELECT resultOf( myfunct('foo','bar'))
with no extra columnname/type to declare. If such function does not exits built-in, let's create it, I don't mind.

If I understood correctly you want
Call a function returning a select query as text
Run that query to get the result.
Number and type of columns are dynamic
1. Using Do Block:
DO
$$
declare
ref_cursor refcursor:='mycursor';
begin
open ref_cursor for execute (select * from my_funct('foo','bar')) ;
end;
$$;
--Fetch all data from cursor
Fetch all from mycursor;
2. Using Function returning refcursor:
You can create a function like below:
create function my_funct1(param1 text) returns refcursor as
$$
declare
ref_cursor refcursor:='mycursor';
begin
open ref_cursor for execute param1;
return ref_cursor;
end;
$$
language plpgsql
To call above function use following code:
begin ;
select my_funct1((select * from my_funct('foo','bar')) );
fetch all from mycursor;
commit;
DEMO

Related

How do I return a table from a function with a bespoke column name?

This function works:
CREATE OR REPLACE FUNCTION public.a()
RETURNS TABLE(a text)
LANGUAGE plpgsql
AS $function$
BEGIN
return query execute
'select a from ztable';
END;
$function$;
But when I try to add some text to the column name:
CREATE OR REPLACE FUNCTION public.a(prefix text)
RETURNS TABLE(a text)
LANGUAGE plpgsql
AS $function$
BEGIN
return query execute
'select a as $1_a from ztable' using prefix;
END;
$function$;
This just fails as a syntax error on $1.
Or:
CREATE OR REPLACE FUNCTION public.a(prefix text)
RETURNS TABLE(a text)
LANGUAGE plpgsql
AS $function$
BEGIN
return query execute
'select a as '||prefix||'_a from ztable';
END;
$function$;
select * from a('some prefix') doesn't work.
Is there some other syntax that does the job?
That's simply not possible. SQL does not allow dynamic column names.
You must assign a column alias with the call. Like:
SELECT a AS prefix_a FROM public.a();
Or in a column definition list directly attached to the function:
SELECT * FROM public.a() AS f(prefix_a);
Or, while dealing with a single output column, even just:
SELECT * FROM public.a() AS prefix_a;
See:
RETURNING rows using unnest()?

Procedure in Redshift Return "SELECT query has no destination for result data" Error

I keep getting the "SELECT query has no destination for result data" error upon calling this test procedure. What am I doing wrong? I did try adding the RETURN() command prior to SELECT statement but that didn't work either.
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (OUT ColumnName VARCHAR(9))
AS $$
BEGIN
SELECT TOP 10 ColumnName FROM SchemaName.TableName where ColumnName is not null;
END;
$$
LANGUAGE plpgsql;
CALL SchemaName.SP_Testing_Creating_Procedure();
As John mentioned you need to put the result into OUT column, examples of using IN, OUT and INOUT parameters you can find here
But if you need to return a few rows as a result, you have to use refcursor
as it's described here
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (INOUT result refcursor)
AS $$
BEGIN
OPEN result FOR
SELECT TOP 10 ColumnName
FROM SchemaName.TableName
WHERE ColumnName IS NOT null;
END;
$$
LANGUAGE plpgsql;
Then you can call the stored procedure in a transaction
BEGIN;
CALL logs.SP_Testing_Creating_Procedure('mycursor');
FETCH ALL FROM mycursor;
COMMIT;
another option is temp table which is also described in the above doc
Your procedure is running a SELECT command, but it is not doing anything with the results.
If your intention was to return a result set, you will need to put data in the OUT column.
See: Returning a result set - Amazon Redshift

Postgres function to return Table into variables

How can I capture different columns into different variables like so (note this is only pseudocode so I am assuming it will cause errors. Example taken from here)
create or replace function get_film (
p_pattern varchar
)
returns table (
film_title varchar,
film_release_year int
)
language plpgsql
as $$
begin
return query
select
title,
release_year::integer
from
film
where
title ilike p_pattern;
end;$$
create or replace function get_film_into_variables (
p_pattern varchar
)
returns null
language plpgsql
as $$
declare
v_title varchar,
v_release_year integer
begin
SELECT
get_film (p_pattern)
INTO
v_title,
v_release_year;
end;$$
Assuming you have some purpose for the variables after retrieving them not just ending the function your "get_film_into_variables" is almost there. But first let's backup just a bit. A function that returns a table does just that, you can use the results just like a table stored on disk (it just goes away after query or calling function ends). To that end only a slight change to the "get_film_into_variables" function is required. The "get_film" becomes the object of the FROM clause. Also change the returns null, to returns void. So
create or replace function get_film_into_variables (
p_pattern varchar
)
returns void
language plpgsql
as $$
declare
v_title varchar;
v_release_year integer;
begin
select *
from get_film (p_pattern)
INTO
v_title,
v_release_year;
end;
$$;
The above works for a single row returned by a function returning table. However for a return of multiple rows you process the results of the table returning function just lake you would an actual table - with a cursor.
create or replace
function get_film_into_variables2(p_pattern varchar)
returns void
language plpgsql
as $$
declare
k_message_template constant text = 'The film "%s" was released in %s.';
v_title varchar;
v_release_year integer;
v_film_message varchar;
c_film cursor (c_pattern varchar) for
select * from get_film (c_pattern);
begin
open c_film (p_pattern);
loop
fetch c_film
into v_title
, v_release_year;
exit when not found;
v_film_message = format( k_message_template,v_title,v_release_year::text);
raise notice using
message = v_film_message;
end loop;
end;
$$;
BTW: the get_film function can be turned into a SQL function. See fiddle here. For demo purposes get_film_into_variable routines return a message.

How to read multiple refcursor return by other procedure to another procedure

i'm having one procedure which returns setof cursors
Now i have to call that procedure to another procedure and access the data
that return by that procedure
is their any way to do this in postgres.
This is code for 1st procedure,
CREATE OR REPLACE FUNCTION public.returns_multiple_cursor( )
RETURNS SETOF refcursor
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
_daily refcursor := 'first_cur';
_fac_hourly refcursor := 'second_cur';
BEGIN
open first_cur for
select * from x;
return next first_cur;
open second_cur for
select * from y;
return second_cur;
END
$function$;
ALTER FUNCTION public.returns_multiple_cursor();
Here code for other second procedure
CREATE OR REPLACE FUNCTION public.access_cursor( )
RETURNS SETOF refcursor
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
BEGIN
-- what code will be here to access the cursor data in this procedure
select public.returns_multiple_cursor();
END;
ALTER FUNCTION public.access_cursor();
Unfortunately, you cannot use the FOR <recordvar> IN <cursor> loop, because it only works for bound cursors (which refcursors are not).
But you can still loop through them, with the old-fashioned FETCH:
declare
rec record;
cur refcursor;
begin
for cur in select returns_multiple_cursor() loop
loop
fetch next from cur into rec;
exit when not found;
-- do whatever you want with the single rows here
end loop;
close cur;
end loop;
end
Unfortunately, there is still another limitation: PostgreSQL caches the first cursor's plan (at least, it seems it does something like that), so you must use cursors, which uses the same column types (you'll have to use the same column names anyway, to be able to refer them in the inner loop, like rec.col1).
Complete, working example: http://rextester.com/FNWG91106 (see f.ex. what happens, when you remove casting from the cursors' queries).
If you have fix number of cursors (like in your example), but differently structured underlying queries, it might be easier to declare your returns_multiple_cursor as:
create or replace function returns_multiple_cursor(out first_cur refcursor,
out second_cur refcursor)
-- returns record (optional)
language plpgsql
-- ...
This way, you could access your cursors more directly in the calling context.
Update: it seems that when you don't use explicit column names, just generic record processing (via f.ex. JSON or hstore), plan caching does not cause any trouble:
http://rextester.com/QHR6096

Calling a function that returns a refcursor

I am using Postgresql 8.3 and have the following simple function that will return a refcursor to the client
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR;
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
Now , I can use the following SQL commands to call this function and manipulate the returned cursor ,but the cursor name is automatically generated by the PostgreSQL
BEGIN;
SELECT function_1(); --It will output the generated cursor name , for example , "<unnamed portal 11>" ;
FETCH 4 from "<unnamed portal 11>";
COMMIT;
Besides explicitly declaring the cursor name as the input parameter of the function as described by 38.7.3.5. Returning Cursors, can I declare my own cursor name and use this cursor name to manipulate the returned cursor instead of Postgresql automatically generates for me ?
If not, are there any commands that can get the generated cursor name ?
I'm not quite sure from wich version of Postgre this is available (in 8.4 it is valid) but i found quite easiest to define the cursor name when you declare it, like this:
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR := 'mycursor';
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
And then you can get it like this:
BEGIN;
SELECT function_1();
FETCH 4 from mycursor;
COMMIT;
I find this method less cumbersome.
Hope that helps.
Yes, use:
CREATE OR REPLACE FUNCTION function_1(refcursor) RETURNS refcursor AS $$
BEGIN
OPEN $1 FOR SELECT * FROM some_table;
RETURN $1;
END;
$$ LANGUAGE plpgsql;
Result:
SELECT function_1('myowncursorname');
function_1
-----------------
myowncursorname
(1 row)
It looks like auto-generated name is <unnamed portal n>, where n is natural number (from 1).
EDIT:
As another way you could use pg_cursors view with such query to obtain generated cursor name:
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
For example:
BEGIN;
SELECT function_1();
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
COMMIT;
Result:
function_1
--------------------
<unnamed portal 3>
(1 row)
name
--------------------
<unnamed portal 3>
(1 row)