Declare a variable of a table type in postgres - sql

I need to write a stored procudere like the following:
CREATE OR REPLACE FUNCTION foo() RETURNS TABLE(user_id integer, count bigint) AS $$
some_array integer[];
ret_val __WHAT_TYPE_;
BEGIN
FOR i IN 1 .. array_upper(some_array, 1)
LOOP
//modify the ret_val
END LOOP;
RETURN ret_val;
END $$
LANGUAGE plpgsql;
But I don't know what type of ret_val I should declare?

In a function returning a table you do not need a variable for returned value.
The columns of the table are treated as OUT parameters.
You can assign values to them and use RETURN NEXT, e.g.:
CREATE OR REPLACE FUNCTION foo()
RETURNS TABLE(user_id integer, counts bigint) AS $$
DECLARE
i integer;
BEGIN
FOR i IN 1..4
LOOP
user_id = i;
counts = i* i;
RETURN NEXT;
END LOOP;
END $$
LANGUAGE plpgsql;
SELECT * FROM foo();
user_id | counts
---------+--------
1 | 1
2 | 4
3 | 9
4 | 16
(4 rows)

Related

Getting an array return on function

I would like to have this function return as an array which contains all ID (integer) from this query, but i am stuck here:
CREATE OR REPLACE FUNCTION public.all_id(
prm_id integer)
RETURNS SETOF integer
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
all_id integer;
-- all_id integer[]; gives an error, while integer only returns last value
BEGIN
SELECT id
COLLECT INTO all_id
FROM subject_data
WHERE sab_subject = (
SELECT sab_subject
FROM subject_data
WHERE id = prm_id
);
RETURN NEXT all_id;
END;
$function$;
SELECT * FROM public.all_id(1);
here's an example of fn:
t=# create or replace function ar() returns int[] as $$
declare ia int[];
begin
select array_agg(oid::int) into ia from pg_database;
return ia;
end;
$$ language plpgsql;
CREATE FUNCTION
t=# select * from ar();
ar
-----------------------------------------------------------
{13505,16384,1,13504,16419,16816,17135,25542,25679,25723}
(1 row)
SETOF would return "table", language is not literal and thus does not require single quotes, and so on...
as a_horse_with_no_name correctly brings out, you don't need plpgsql for this. A simple query will work:
SELECT array_agg(id)
FROM subject_data
WHERE sab_subject = (
SELECT sab_subject
FROM subject_data
WHERE id = PRM_ID_VALUE
)

NodeJS and PostgreSQL function returns tuple, not row

I'm running PostgreSQL and NodeJS.
In PostgreSQL I have a custom function dummy:
... RETURNS RECORD AS $$
...
DECLARE ret RECORD
...
RETURN ret;
END;
$$ LANGUAGE plpgsql;
In NodeJS this returns a tuple, as a string:
(x,y,z)
So I have to manually split the string and read the parts...
Is it possible to have PostgreSQL return the tuple as a rowor similar, so I can use data.x, data.y and data.zin NodeJS instead?
fn():
t=# create or replace function f() returns record as $$ declare ret record; begin for ret in (select oid::int,datname::text from pg_database limit 1) loop return ret; end loop; end; $$ language plpgsql;
CREATE FUNCTION
your call:
t=# select f();
f
------------------
(13505,postgres)
(1 row)
expected call:
t=# select * from f() as r(o int,n text);
o | n
-------+----------
13505 | postgres
(1 row)
and if you want to predefine the structure of record to be called implicitely, you can create a dummy fn():
t=# create or replace function dummy() returns table (a int,b text) as $$ begin return query select * from f() as r(o int,n text); end; $$ language plpgsql;
CREATE FUNCTION
t=# select * from dummy();
a | b
-------+----------
13505 | postgres
(1 row)
of if you want to avoid FROM:
t=# select (dummy()).*;
a | b
-------+----------
13505 | postgres
(1 row)

How Do I use or properly return a value from my PostgreSQL function?

CREATE OR REPLACE FUNCTION data.first()
AS $BODY$
DECLARE
res numeric;
BEGIN
PERFORM data.second(5,3,4);
IF(res > 10)THEN
something
ELSEIF(res < 10)THEN
something else
END IF
END;
$BODY$;
=========================================
CREATE OR REPLACE FUNCTION data.second(
a numeric,
b numeric,
c numeric
OUT res numeric
)
RETURNS numeric
AS $BODY$
BEGIN
res = a + b;
END;
$BODY$;
How do I use res in the parent function?
don't specify both OUT and function returns:
t=# CREATE OR REPLACE FUNCTION data.second(
a numeric,
b numeric,
c numeric,
OUT res numeric
)
AS $BODY$
DECLARE
BEGIN
res = a + b;
END;
$BODY$ language plpgsql;
CREATE FUNCTION
if you want to use the return of function ,use select into VAR, perform will just execute function discarding its output:
t=# CREATE OR REPLACE FUNCTION data.first() returns text
AS $BODY$
DECLARE
res numeric;
BEGIN
SELECT data.second(5,3,4) INTO res;
IF(res > 5)THEN
raise info 'second returned %',res;
END IF;
RETURN 'here is the return';
END;
$BODY$ language plpgsql;
CREATE FUNCTION
finaly:
t=# select * from data.first();
INFO: second returned 8
first
--------------------
here is the return
(1 row)
https://www.postgresql.org/docs/current/static/plpgsql.html

query has no destination for result data - PostgreSQL

I have created the following stored procedure in PostgreSQL:
CREATE OR REPLACE function incomingdel(IN del_ID varchar) RETURNS VOID AS $$
DECLARE xyz integer;
BEGIN
SELECT * INTO xyz FROM incomingcheck(cast(del_ID as integer));
IF xyz <> 1
THEN
SELECT * INTO xyz FROM perfdel(cast(del_ID as integer));
END IF;
END
$$ LANGUAGE plpgsql
even though the function returns VOID, I am still getting
Error: query has no destination for result data
when i execute the function. Can someone please help?
Thanks
When you do SELECT * INTO ... in a PL/pgSQL function you need to supply a variable of type record or of the row type of the row source, even if the function only returns an integer. The functions incomingcheck(int) and perfdel(int) are obviously returning a single integer in which case you can simplify your function:
CREATE FUNCTION incomingdel(del_ID integer) RETURNS VOID AS $$
DECLARE
xyz integer;
BEGIN
xyz := incomingcheck(del_ID);
IF xyz <> 1 THEN
xyz := perfdel(del_ID);
END IF;
-- Do something with xyz
END; $$ LANGUAGE plpgsql;
If the functionality is actually in the called functions (so you do not process the xyz value), then it becomes simpler still:
CREATE FUNCTION incomingdel(del_ID integer) RETURNS VOID AS $$
BEGIN
IF incomingcheck(del_ID) <> 1 THEN
perfdel(del_ID);
END IF;
END; $$ LANGUAGE plpgsql;

passing cursor values into another function

*i have a function which will delete the rows in the table for the given input id, the input is given to the function by another cursor_function.*
select * from t1;
id | col1
----+-------
1 | user1
2 | user2
3 | user3
4 | user4
5 | user5
(5 rows)
create or replace function del_t1(int) returns void as $$
declare
a alias for $1;
begin
delete from t1 where id = a;
return;
end;
$$language plpgsql;
create or replace function del_cur(ref refcursor) returns void as $$
declare
a int;
begin
open ref scroll for select id from t1 where id > 3 order by id desc;
fetch first from ref into a;
perform del_t1(a);
loop
a := 0;
fetch next from ref into a;
perform del_t1(a);
if (a=0) then
exit;
end if;
end loop;
end;
$$ language plpgsql;
when the function is executed,
postgres# select del_cur('t1');
it shows no error, no outputs, cursor just blinks, plz help me to solve this, this is small description of my big database tables, i need a cursor function which will pass its values one by one to another function.
In your example the function del_cur(refcursor) is declared to take a cursor. But you never actually use it inside the function - the construct makes no sense at all.
What you are trying to do should be much easier with the implicit cursor of a FOR loop:
CREATE OR REPLACE FUNCTION del_stuff()
RETURNS void AS
$BODY$
DECLARE
_a int;
BEGIN
FOR _a IN
SELECT id FROM t1 WHERE id > 3 ORDER BY id DESC
LOOP
DELETE FROM t1 WHERE id = _a;
-- do other stuff?
END LOOP;
END;
$BODY$ LANGUAGE plpgsql;
I don't understand the need to delete the rows one by one in descending order. Are triggers involved? Maybe the whole thing can be as simple as:
DELETE FROM t1 WHERE id > 3;