Return multiple rows from plpgsql function - function

I have the below function:
CREATE OR REPLACE FUNCTION function1() RETURNS TABLE(foo1 VARCHAR, foo2 VARCHAR) AS $$
BEGIN
RETURN QUERY SELECT e.col1, e.col2 FROM my_table e;
END;
$$ LANGUAGE plpgsql;
It returns something like this:
function1
record
|--------------|
(a,b)
(c,d)
But I'm expecting a result analog to a query like this:
SELECT e.col1, e.col2 FROM my_table e;
col1 col2
|-----|-----|
a b
c d
Because I want to execute the function a get the separates columns values in a java resultSet and iterate accros them. Thanks!

You need to do
select * from function1();

Related

Postgres JSON Array data processing

Have a table "json_test" and inserted the following record:
create table json_test ( v json);
insert into json_test values ('{"facilityId": ["20","30","40","50","51"]}')
SELECT trim(json_array_elements_text(v->'facilityId') ) from json_test
The above select lists the facility ID as individual rows.
I need the same rows in a Postgres function to insert the record into another table. I wrote the following code to return i. The output of the v_status when checked is (20,,,,,,,,,,,,). I need to get just 20, but I am unable to get that.
for i in SELECT json_array_elements_text(v->'facilityId') from json_test
loop
v_status:= i;
end loop;
You have not specified entire function definition in your question.
Assuming you have DDL:
CREATE TABLE json_test(
id SERIAL PRIMARY KEY,
v JSON
);
INSERT INTO json_test(v) VALUES
('{"facilityId": ["20","30","40","50","51"]}'::JSON);
You can check full PL/pgSQL guide as a reference, but your function may be defined as the following:
CREATE OR REPLACE FUNCTION get_facility_ids(rid INTEGER)
RETURNS SETOF INTEGER AS $$
DECLARE
t TEXT;
BEGIN
FOR t IN SELECT json_array_elements_text(v->'facilityId')
FROM json_test WHERE id = rid
LOOP
RETURN NEXT t;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT get_facility_ids(1) AS facultyId;
Just for your information, you can INSERT records from SELECT statements. Check the documentation.

Calling table function from procedure (pl sql)

I am having big trouble calling a function that returns a table from my procedure. I believe there is something wrong with my declaration so its not compiling. Here is my code.. the developer underlines with red the SELECT "D_ID" and from table "(IREL_FN (X))"; . And here is my code.
CREATE OR replace PROCEDURE Irrelevant_skata (x NUMBER)
AS
d_id T_ID_TABLE;
BEGIN
DECLARE
TYPE yo_table
IS
TABLE OF YO_TABLE;
YO_TABLE "(IREL_FN (X))"%TYPE;
id NUMBER;
BEGIN
SELECT "D_ID"
INTO yo_table
FROM TABLE "(IREL_FN (X))";
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('NO DATA FOUND');
END;
END irrelevant_skata;
And the function
CREATE OR replace FUNCTION Irel_fn (x IN NUMBER)
RETURN T_ID_TABLE
AS
id T_ID_TABLE;
BEGIN
BEGIN
SELECT Cast(MULTISET(SELECT "id"
FROM "somethingcopy"
WHERE "kati" IN (SELECT "auto"
FROM "ekeino"
WHERE "id" = x)) AS T_ID_TABLE)
INTO id
FROM dual;
RETURN id;
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('null');
END;
END irel_fn;
It's hard to answer without knowing what you're trying to do.
YO_TABLE "(IREL_FN (X))"%TYPE;
This doesn't make any sense. You can't declare a variable to be %type of a function. Looking up at YO_TABLE declaration, you write
DECLARE
TYPE yo_table
IS
TABLE OF YO_TABLE;
Huh? table declaration is table of same variable you're declaring?
And this:
SELECT "D_ID"
INTO yo_table
FROM TABLE "(IREL_FN (X))";
You don't need quotes when casting table, and the x in IREL_FN (X) is a formal parameter, you need to replace it with the actual value what you need to pass
create or replace
PROCEDURE IRRELEVANT_SKATA (INSID IN NUMBER) AS ID T_ID_TABLE ;
BEGIN
DECLARE
YO_TABLE T_ID_TABLE;
BEGIN
select ID
into YO_TABLE
from table(IREL_FN(INSID));
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('NO DATA FOUND');
END;
END IRRELEVANT_TWEET;
<-----------------------------FUNCTION---------------------------------->
create or replace
FUNCTION IREL_FN ( D_ID IN NUMBER ) RETURN T_ID_TABLE AS
ID T_ID_TABLE;
BEGIN
BEGIN
SELECT CAST(
MULTISET(
SELECT "Id"
FROM "SOMETHINGCOPY"
WHERE "KATI" = (SELECT "EKEINO" FROM "AUTO" WHERE "Id"=D_ID)
INTO ID
FROM DUAL;
return ID;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('null');
END;
END IREL_FN;
I hope I helped :)
I am answering to your question marked as duplicate (the problem with exact fetch).
I rewrote your code in the following way, hope it helps. I makes the Irel_fn to be a pipelined function, however you can still write Cast multiset if you like , however you need to use type constructor as well.
create table auto(id number)
this table is instead of your source "AUTO" (so I could compile it).
create or replace type t_id as object (id number);
/
Create or replace type t_id_table is table of t_id;
/
create or replace FUNCTION Irel_fn (x IN NUMBER) RETURN T_ID_TABLE PIPELINED
as
BEGIN
for rec in (select id from auto where id=x)
loop
Pipe row (t_id(rec.id));
end loop;
return;
end;
/
create or replace procedure Irrelevant_skata (insid in NUMBER) is
bob t_id_table;
BEGIN
select t_id(id) bulk collect into bob from table(irel_fn(insid));
END;

PostgreSQL: Getting result of a function in a single column in PostgreSQL

Trying to display the result in the form of table with different columns, but getting all result in a single column.
--My Function
create or replace function test1()
returns table ( "Fname" varchar(20),"Lname" varchar(20),"A-B" bigint,"C-D" bigint,
"E-F" bigint ) as
$body$
begin
return query
SELECT tb."Fname",tb."Lname",count(tb."City"='A-B' OR NULL) AS "A-B",
count(tb."City"='C-D' OR NULL) AS "C-D",
count(tb."City"='E-F' OR NULL) AS "E-F"
FROM "Table1" tb
WHERE tb."City" in ('A-B','C-D','E-F')
GROUP BY 1,2
ORDER BY 1,2;
end
$body$
language plpgsql;
In instead of
select test1()
do
select * from test1()
You need no plgpsql for this. This is just a plain query.
But supposing you just want to test it: How do you call the function?
For table returning functions you do: select * from f1();.
For functions returning one value you do select f1();.

PostgreSQL: Call a Function More Than Once in FROM Clause

How can I call a function which returns records more than once in FROM clause? I understand that I have to specify a 'column definition list' when using a function that returns records. But how can I then use aliases for that function?
Example:
CREATE OR REPLACE FUNCTION foo(which_foo int) RETURNS SETOF RECORD AS
$BODY$BEGIN
IF which_foo=0 THEN
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
ELSE
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
END IF;
END$BODY$
LANGUAGE plpgsql;
SELECT * FROM foo(0) AS (a int, b int);;
SELECT * FROM foo(1) AS (c int, d int);
SELECT * FROM foo(0) AS (a int, b int), foo(1) AS (c int, d int);
The last select statement will fail with:
ERROR: table name "foo" specified more than once
I want to keep using the column definition list, because the function I want to use in the end has to be as generic as possible.
SELECT f0.*, f1.*
FROM
foo(0) AS f0 (a int, b int),
foo(1) AS f1 (c int, d int);
I understand that I have to specify a 'column definition list' when
using a function that returns records.
No, you do not. I wouldn't operate with anonymous records. Declare the return type, since you already know it:
CREATE OR REPLACE FUNCTION foo(which_foo int)
RETURNS TABLE (a int, b int) AS
$func$
BEGIN
IF which_foo = 0 THEN
RETURN QUERY SELECT 1,2;
ELSE
RETURN QUERY SELECT 1,2;
END IF;
END
$func$ LANGUAGE plpgsql;
And assuming you do not want to combine multiple calls into one row, you should use UNION ALL:
SELECT * FROM foo(0)
UNION ALL
SELECT * FROM foo(1);

How to return a table, rows or record from a function in PostgreSQL 9?

I have a table called person which has id,name,status and I want to return rows as a result of a function with 1 parameter (name).
Can anyone help me? Please make it easy, because im very noob in PostgreSQL.
This is my code from a normal function
create or replace function fn_list(vname varchar) returns void as $$
begin
SELECT id,name,status from usuario WHERE name= vname;
end;
$$ language plpgsql;
I know I'm returning a void function but how can I do if I want a list of rows?
I know that pipelined returns in Oracle does this, so I used that to find 'RETURN NEXT' from plpgsql:
http://www.postgresql.org/message-id/007b01c6dc31$ae395920$0a00a8c0#trivadis.com
Also on grokbase:
http://grokbase.com/t/postgresql/pgsql-performance/069kcttrfr/pipelined-functions-in-postgres
(Edit to add official documentation): http://www.postgresql.org/docs/9.2/static/plpgsql-control-structures.html
Killer, I will have to make use of this myself.
Editing one more time to add in some demo code (directly from postgresql.org documentation):
CREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT);
INSERT INTO foo VALUES (1, 2, 'three');
INSERT INTO foo VALUES (4, 5, 'six');
CREATE OR REPLACE FUNCTION getAllFoo() RETURNS SETOF foo AS
$BODY$
DECLARE
r foo%rowtype;
BEGIN
FOR r IN SELECT * FROM foo
WHERE fooid > 0
LOOP
-- can do some processing here
RETURN NEXT r; -- return current row of SELECT
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
SELECT * FROM getallfoo();
Using a loop to return the result of a query is slow and inefficient. The overhead of PL/pgSQL is not even required for this.
The best solution is:
create or replace function fn_list(vname varchar)
returns table(id integer, name text, status text)
as $$
SELECT id,name,status
from usuario
WHERE name= vname;
$$ language sql;
If PL/pgSQL is needed because some other procedural code needs to run before the query, then return query should be used instead of a loop:
create or replace function fn_list(vname varchar)
returns table(id integer, name text, status text)
as $$
begin
-- do some work....
return query
SELECT id,name,status
from usuario
WHERE name= vname;
end;
$$ language plpgsql;
Then call it using:
select *
from fn_list('Arthur');
Many answers here omit important parts of using functions. Here's an updated way of using functions in postgres (including declaration, variables, args, return values, and running). Below is an over-baked example of updating the tweet on the bottom right "blurb" with "hello world".
id (serial)
pub_id (text)
tweet (text)
1
abc
hello world
2
def
blurb
-- Optional drop if replace fails below.
drop function if exists sync_tweets(text, text);
create or replace function sync_tweets(
src_pub_id text, -- function arguments
dst_pub_id text
) returns setof tweets as -- i.e. rows. int, text work too
$$
declare
src_id int; -- temp function variables (not args)
dest_id int;
src_tweet text;
begin
-- query result into a temp variable
src_id := (select id from tweets where pub_id = src_pub_id);
-- query result into a temp variable (another way)
select tweet into src_tweet from tweets where id = src_id;
dest_id := (select id from tweets where pub_id = dst_pub_id);
update tweets set tweet=src_tweet where id = dest_id;
return query -- i.e. rows, return 0 with return int above works too
select * from tweets where pub_id in (src_pub_id, dst_pub_id);
end
$$ language plpgsql; -- need the language to avoid ERROR 42P13
-- Run it!
select * from sync_tweets('abc', 'def');
/*
Outputs
__________________________________________________
| id (serial) | pub_id (text) | tweet (text) |
|---------------|-----------------|----------------|
| 1 | abc | hello world |
| 2 | def | blurb |
--------------------------------------------------
*/