Call a FUNCTION from inside a PROCEDURE in PostgreSQL - postgresql

Right now, we are migrating a stored procedure from SQL Server to Postgres.
We have a procedure which does some write operations and after that It will call a list function to list all the data currently existing.
create or replace procedure public.tree_create()
language plpgsql
as
$$
BEGIN
/* Insertion code goes here. */
/* return result. */
select * from public.tree_list();
END;
$$;
This will throw error
[42601] ERROR: query has no destination for result data Hint: If you want to discard the results of a SELECT, use PERFORM instead. Where: PL/pgSQL function public.tree_create() line 4 at SQL statement
So how can we return data by calling the function. FYI: The function is working fine and when we call it using select * from list_tree() It will returns the data.
So how exactly can we call FUNCTION inside STORED PROCEDURE to return results? Or is there any other methods to follow?

Procedures aren't meant to return results. You need to convert it into a function:
create or replace function public.tree_create()
returns table (... same signature as tree_list() ...)
language plpgsql
as
$$
BEGIN
/* Insertion code goes here. */
return query
select * from public.tree_list();
END;
$$;
Then use it like this:
select *
from tree_create();

Related

Postgresql - Stored Procedure that returns a table result set

Im new to PostgreSQL v.13 and want to create a Stored Procedure that will receive an integer value and then return the results from a table.
I have this:
create or replace procedure public.sp_message_template_get(
templateid int
) language plpgsql AS $$
begin
-- subtracting the amount from the sender's account
select * from public.message_template;
--commit;
end;
$$
Then I try to call it by using:
call public.sp_message_template_get(1);
And I get the following error:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function sp_message_template_get(integer) line 6 at SQL statement
SQL state: 42601
Any clue?
Thanks
Create a sql function.
create or replace function message_template_get(templateid integer)
returns setof message_template language sql as
$$
-- subtracting the amount from the sender's account (sql query)
select * from public.message_template;
$$;
If there is a reason to use plpgsql language then use return query.
create or replace function message_template_get(templateid integer)
returns setof message_template language plpgsql as
$$
begin
-- subtracting the amount from the sender's account
return query select * from public.message_template;
-- maybe other statements here
end;
$$;
Please note that commit is not necessary and illegal in a function body. More than one return query or return next statements are possible.

Why can you select a calculation and get a result, but can't get a result when selecting a function that has the same calculation?

In plpgsql, I'm trying to test a calculation. To see a result in my sql editor, I can do the following:
select 3 * 5;
Then when I highlight the code in my editor and run the query, I get the result ?column? with a row with the value 15.
But if a create a function like this:
CREATE OR REPLACE FUNCTION do_something() RETURNS VOID AS $$
BEGIN SELECT 3 * 5; END;
$$ LANGUAGE PLPGSQL;
and then highlight and run the query:
SELECT do_something();
I get an error saying that the "query has no destination for result data".
I just want to be able to test blocks of code and see results even if it's not associated with a table. What's the best way to do that?
Your first error is that the function is declared to return nothing return void. If you want to return an integer, you need to change that to return int.
Additionally in PL/pgSQL, you need to use return to return a value, not a SELECT statement.
CREATE OR REPLACE FUNCTION do_something()
RETURNS int
AS $$
BEGIN
return 3 * 5;
END;
$$ LANGUAGE PLPGSQL;
Note that for a simple calculation like that a language SQL function is more efficient, as PL/pgSQL does have some overhead.
CREATE OR REPLACE FUNCTION do_something()
RETURNS int
AS $$
select 3 * 5;
$$ LANGUAGE sql;

Function's final statement must be SELECT or INSERT UPDATE DELETE RETURNING

CREATE FUNCTION retrieve_add_friends(user_id text[])
RETURNS SETOF user_rows AS
$BODY$
BEGIN
FOR user_rows IN EXECUTE SELECT * FROM user_details where user_id= $1
LOOP
FOR user_friends IN EXECUTE SELECT * FROM user_add_friends where user_id= $1
LOOP
IF user_rows.user_id!=user_friends.user_friend_id THEN
RETURN NEXT user_rows;
END IF;
END LOOP;
RETURN;
END LOOP;
RETURN;
END
$BODY$
language plpgsql VOLATILE;
When I execute this I get following error:
ERROR: return type mismatch in function declared to return user_details
DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.
CONTEXT: SQL function "retrieve_add_friends"
Can anyone help me out with this?
The function displayed is a PL/pgSQL function.
You are calling a different function, an SQL function, obviously (for which the error msg would make sense):
SQL function "retrieve_add_friends"
Same function name, but different arguments (and possibly in a different database schema). Are you aware of function overloading and its implications?
Related:
ERROR: function addgeometrycolumn is not unique
For a quick diagnosis:
SELECT oid::regprocedure AS function_signature, *
FROM pg_proc
WHERE proname = 'retrieve_add_friends';
All that aside, the function displayed has multiple errors and can be replaced with plain SELECT.

Error Message : Query has no destination for result data

I am new to postgreSQL. I am trying to convert SQL store procedure into postgreSQL store function. I tried Like below store function created successfully but when I am trying to execute I am getting following error message. I am not getting where I need to replace PERFORM.
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
SQL Store Procedure
CREATE PROCEDURE [dbo].[roomType]
#intInstId int
AS
BEGIN
SELECT
nClientRoomTypeID,sClientRTDesc,sClientRTName,sClientRTCode
FROM
ClientRoomType
WHERE
ClientRoomType.nInstID=#intInstId
ORDER BY
ClientRoomType.sClientRTCode
END
GO
PostgreSQl Store Function
CREATE OR REPLACE FUNCTION roomType (int_inst_id int)
RETURNS VOID
AS $$
BEGIN
SELECT
nclient_room_type_id,sclient_rt_desc,sclient_rt_name,sclient_rt_code
FROM
clientroomtype
WHERE
clientroomtype.ninst_id=int_inst_id
ORDER BY
clientroomtype.sclient_rt_code;
END;
$$ LANGUAGE plpgsql;
I assume you're attempting to return the query result with your function. You actually do not need plpgsql language for this, but in case you need it for somthing else, use this syntax:
CREATE OR REPLACE FUNCTION roomType (int_inst_id int)
RETURNS TABLE (res_nclient_room_type_id INT,res_sclient_rt_desc TEXT,res_sclient_rt_name TEXT, res_sclient_rt_code TEXT)
AS $$
BEGIN
RETURN QUERY
SELECT
nclient_room_type_id,sclient_rt_desc,sclient_rt_name,sclient_rt_code
FROM
clientroomtype
WHERE
clientroomtype.ninst_id=int_inst_id
ORDER BY
clientroomtype.sclient_rt_code;
END;
$$ LANGUAGE plpgsql;
How to use it?
SELECT * FROM roomType(1);
Since I do not have your data, I cannot test it. But it follows this principle:
CREATE OR REPLACE FUNCTION f ()
RETURNS TABLE (b boolean, x int)
AS $$
BEGIN
RETURN QUERY SELECT TRUE, 1;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM f();
b | x
---+---
t | 1
(1 Zeile)

PL/pgSQL functions - loop through specific column and execute second query in loop

As you can see in title, I want to loop through specific column which holds building IDs and then function will execute a second query that uses these looped values and show query result in PostgreSQL.
Please note that the code below:
CREATE OR REPLACE FUNCTION getBID() RETURNS SETOF building AS
$BODY$
DECLARE
r building%ROWTYPE;
BEGIN
FOR r IN EXECUTE 'SELECT point_id FROM building'
LOOP
RETURN QUERY EXECUTE 'SELECT gid, nof, year
FROM building
WHERE point_id = ' || r;
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
SELECT * FROM getBID();
My building IDs are integer values. I wonder two aspects as follows:
"r" variable should be declared as "integer"?
my second query should be used in loop, too?
Thanks in advance...
For a trivial task like that use a simple SQL function instead:
CREATE OR REPLACE FUNCTION get_buildings()
RETURNS SETOF building AS
'SELECT * FROM building' LANGUAGE sql;
Or just:
SELECT * FROM building;
Here is one example for an actual FOR loop filling a single column in plpgsql:
Returning results from a function in 'select statement' format
Another example with an anonymous record:
Loop on tables with PL/pgSQL in Postgres 9.0+
Try a search. There are many more.