PostgreSql 12 JDBC multiple resultset, can only get the first resultset - postgresql

Want JDBC to get multiple result-sets from PostgreSql 12 function. JDBC version org.postgresql/postgresql/42.2.9. The PostgreSql function is here:
create or replace function test()
returns setof refcursor as $$
declare
ret1 refcursor;
ret2 refcursor;
begin
open ret1 for
select 10 as a;
return next ret1;
open ret2 for
select 20 as b;
return next ret2;
end; $$ language plpgsql;
Java code is like this:
stmt = getConnection().prepareCall("{ ? = call test() }");
stmt.registerOutParameter(1, Types.OTHER);
stmt.execute();
rs = (ResultSet)stmt.getObject(1);
if (rs.next()) {
int a = rs.getInt("a");
if (rs.next()) {
int b = rs.getInt("b");
}
}
"a" is successfully retrieved, but the second "rs.next()" returns false. Googled a lot but couldn't make it work. How can I get the 2nd result-set?

This link helped me a lot and the problem was resolved.
...
out ret1 refcursor,
out ret2 refcursor)
returns record as $$
begin
open ret1 for select 10;
open ret2 for select 20;
end; $$ language plpgsql;
Java:
stmt = getConnection().prepareCall("{call test(?,?)}");
stmt.registerOutParameter(1, Types.OTHER);
stmt.registerOutParameter(2, Types.OTHER);
stmt.execute();
ResultSet rs1 = (ResultSet)stmt.getObject(1);
ResultSet rs2 = (ResultSet)stmt.getObject(2);
int a = 0, b = 0;
if (rs1.next()) {
a = rs1.getInt(1);
}
if (rs2.next()) {
b = rs2.getInt(1);
}

Related

Postgresql Simple IF ELSE Statement

In MS SQL I can execute a statement like:
Declare #foo int = 1, #foo1 int = 42
IF #foo <> 0
BEGIN
SELECT #foo
END
ELSE
BEGIN
SELECT #foo, #foo1
END
Does anyone have any idea how to run this statement on postgresql?
EDIT: MS SQL Example like :
CREATE PROCEDURE dbo.spIFtest
#p1 int = 1,
#p2 int = 10,
#isFilter bit = 0
AS
BEGIN
IF #isFilter = 1
BEGIN
SELECT idx FROM rw.octest where idx between #p1 and #p2
END
ELSE
BEGIN
SELECT idx FROM rw.octest
END
END
GO
Using DO With caveats:
DO $$
DECLARE
foo integer := 1;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
PERFORM foo;
ELSE
PERFORM foo, foo1;
END IF;
END;
$$
;
DO cannot return anything.
You can fake a return:
DO $$
DECLARE
foo integer := 0;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
SELECT INTO foo 1;
RAISE NOTICE 'foo is %', foo;
ELSE
SELECT INTO foo, foo1 1, 42 ;
RAISE NOTICE 'foo is %, foo1 is %', foo, foo1;
END IF;
END;
$$
;
NOTICE: foo is 1, foo1 is 42
DO
In PostgreSQL DO Block can execute the queries but they can not return any value.
So the first part of your question is not possible directly in postgresql.
For second part of your question: In PostgreSQL you can use Function (which is very powerful and effective) like below:
create or replace function spiftest()
returns table(idx_ int)
as $$
declare
p1 int := 1;
p2 int := 10;
isfilter boolean := 0;
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
calling above function for result:
select * from spiftest()
You can write it with parameters also like below:
create or replace function spiftest(p1 int, p2 int, isfilter boolean)
returns table(idx_ int)
as $$
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
to call above function
select * from spiftest(1,10,'t')

How to run SELECT queries in PL/pgSQL IF statements

I am trying to run SELECT queries in PL/pgSQL IF statements using the code below:
DO
$do$
DECLARE
query_type real;
arr real[] := array[1];
BEGIN
IF query_type = 1 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster"
WHERE ("Westminster".intersects = false AND "Westminster".area <= 100);
ELSE IF query_type = 0 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster";
END IF;
END
$do$
However I get the following error, ERROR: cannot use RETURN QUERY in a non-SETOF function.
Does anyone know how I can get the above code to work? Thank you.
UPDATE: This ended up working for me:
CREATE OR REPLACE FUNCTION my_function(query_type integer)
RETURNS SETOF "Westminster" LANGUAGE plpgsql as $$
BEGIN
IF query_type = 1 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster"
WHERE ("Westminster".intersects = false AND "Westminster".area <= 100);
ELSIF query_type = 0 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster";
END IF;
END;
$$;
I then called the function like this:
SELECT * FROM my_function(1);
From the documentation:
The code block is treated as though it were the body of a function with no parameters, returning void.
You can use RETURN QUERY only in a function returning SETOF <type> or TABLE(...). Use the table "Westminster" as the resulting type, e.g.:
CREATE OR REPLACE FUNCTION my_function(query_type int)
RETURNS SETOF "Westminster" LANGUAGE plpgsql as $$
BEGIN
IF query_type = 1 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster"
WHERE ("Westminster".intersects = false AND "Westminster".area <= 100);
ELSIF query_type = 0 THEN
RETURN QUERY
SELECT "Westminster".*
FROM "Westminster";
END IF;
END;
$$;
-- exemplary use:
SELECT * FROM my_function(1);
Note the proper use of ELSIF.
I don't think anonymous code blocks support it. Try creating a function and defining its resultset to table, e.g:
CREATE OR REPLACE FUNCTION myfunc() RETURNS TABLE (val INT) AS $$
BEGIN
RETURN QUERY SELECT 1;
END;
$$ LANGUAGE plpgsql;
To call your function you could use:
SELECT * FROM myfunc();
Note: keep in mind that the table declared on the function's header needs to have the same fields returned in the RETURN QUERY statement.

Check Results Count in Postgres Function Before Returning

I have a postgres function that I'd like to return the result of a query, but I'd like it to return nothing if that query matches more than 1 record.
So, something like:
CREATE OR REPLACE FUNCTION myFunc(_a text, _b text)
RETURNS yy
LANGUAGE plpgsql
STABLE
PARALLEL SAFE
AS $$
BEGIN
RETURN QUERY
SELECT *
FROM yy
WHERE a = x
AND b = y;
END;
$$;
Except, it should return nothing if that query matches more than 1 record.
CREATE OR REPLACE FUNCTION myFunc(_a text, _b text)
RETURNS SETOF yy -- To be able to return "nothing"
LANGUAGE plpgsql
STABLE
PARALLEL SAFE
AS $$
DECLARE
result yy;
BEGIN
SELECT *
INTO STRICT result -- STRICT allows to check that exactly one row returned
FROM yy
WHERE a = x
AND b = y;
RETURN NEXT result; -- RETURN NEXT - return yet another row for "RETURNS SETOF" function
EXCEPTION
WHEN no_data_found OR too_many_rows THEN -- When no data or more then one rows
RETURN; -- Nothing to return, just exit
END;
$$;
i guess this can help you out.
CREATE OR REPLACE FUNCTION database.myFunction(
IN text,IN text)
RETURNS TABLE(firstField, secondField, lastField) AS
$BODY$
--sql string is the variable containing the final sql code
declare sql_string text;
declare regs numeric;
begin
--this is what happens in case count<1
sql_string = 'select 0,0,0';
--now we count them
regs = (select count(firstField) from mytable where a=b)::numeric;
--if >=1, then whe get the whole data
if (regs>=1) then
sql_string = 'select firstField,secondField, lastField from mytable where a=b';
end if;
--and return to you...
return query EXECUTE sql_string;
end;

how do I return a bit in postgres

I am new to postgres and trying to setup a function that returns a bit.
I keep getting the error
Function's final statement must be SELECT or INSERT/UPDATE/DELETE
RETURNING.
I understand that
Unless the function is declared to return void, the last statement must be a SELECT, or an INSERT, UPDATE, or DELETE that has a RETURNING clause.
here is the code
CREATE OR REPLACE FUNCTION "f"(...)
RETURNS bit AS
DO $$
Begin
IF someStuff
THEN
0; //also tried select 0 //also tried return 0
ELSE
1; //also tried select 1 //also tried return 0
END IF;
0; //also tried select 0 //also tried return 0
END $$
Where am I going wrong with the syntax?
There are several errors:
the DO is wrong in a function definition
you are missing the specification of the language
in PL/pgSQL you use return to return the function's result
So your function becomes:
CREATE OR REPLACE FUNCTION f(some_value integer)
RETURNS bit AS
$$
Begin
IF (some_value = 1)
THEN
return 0;
ELSE
return 1;
END IF;
END $$
language plpgsql
But you should use boolean instead of bit to return true/false flags:
CREATE OR REPLACE FUNCTION f(some_value integer)
RETURNS boolean AS
$$
Begin
IF (some_value = 1)
THEN
return false;
ELSE
return true;
END IF;
END $$
language plpgsql
If you want to use plpgsql then do as in the a_horse's answer but if you don't need plpgsql do in sql:
create or replace function f(some_value integer)
returns boolean as $$
select some_value = 1;
$$
language sql;
If the function is the one from this question then this will do it:
create or replace function isPersonQualifiedForJob(pid integer, jid)
returns boolean as $$
select exists (
select 1
from
getskillsforjob(jid) j
inner join
getskillsforperson(pid) p on j.skillid = p.skillid
)
$$
language sql;
Checking for exists is much faster then counting since it is enough to find the first match.

How to get the result parameter of a NativeQuery

I want to make this Query:
Select
srid,
substring(srtext
from (position('DATUM["' in srtext)+7)
for (position('ID["' in srtext)+2)
- (position('DATUM["' in srtext)+7))
from spatial_ref_sys
order by substring
So, I create a
Query query = em().createNativeQuery(QUERY)
Also create a Srid object that has a Long srid and a String sridText.
I need to get those values and put into a List.
The substring on sridText, and obviously the srid into Long srid.
Please help!!!
Found the answer. First of all, I did a plpgsql function called getSrid
CREATE OR REPLACE FUNCTION getSRID() returns text[] as $$
declare
resultado text[];
consulta cursor for
Select srid,substring(srtext from (position('DATUM["' in srtext)+7)
for(position('ID["' in srtext)+2)
- (position('DATUM["' in srtext)+7)) as sub
from spatial_ref_sys;
cont int;
i int;
sridd int;
srTextt text;
begin
open consulta;
i=1;
EXECUTE 'SELECT COUNT(*) FROM SPATIAL_REF_SYS' into cont;
resultado := ARRAY[cont];
while(i<cont) loop
fetch consulta into sridd,srTextt;
resultado[i] := sridd;
resultado[i+1] := srTextt;
i:=i+2;
end loop;
return resultado;
end
$$ language plpgsql;
As you see I got a Text[] on return so in my java call I cast the object to String[]:
public List<SridDTO> listaa(){
int i = 0;
List<SridDTO> list = new ArrayList<SridDTO>();
Query query = em().createNativeQuery("Select getSrid()");
String[] vector = (String[]) query.getSingleResult();
while(i<vector.length){
SridDTO sridDTO = new SridDTO(new Long(vector[i]),vector[i+1]);
i = i + 2;
list.add(sridDTO);
}
return list;
}