How to run SELECT queries in PL/pgSQL IF statements - postgresql

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.

Related

how do I get the result of a select within a function in postgresql?

I want to get a table with value 1 as result, but this query returns 0 rows. Why is this happening?
CREATE OR REPLACE FUNCTION test_6()
RETURNS TABLE
(
r int
)
LANGUAGE plpgsql
AS $function$
BEGIN
execute 'SELECT 1 as r';
end;
$function$;
select test_6()
You need to add RETURN QUERY
CREATE OR REPLACE FUNCTION test_6()
RETURNS TABLE
(
r int
)
LANGUAGE plpgsql
AS $function$
BEGIN
RETURN QUERY
execute 'SELECT 1 as r';
end;
$function$;
Also, as was suggested in comments bellow, you should use the function like a table select * from test_6()
And you can use just
RETURN QUERY
SELECT 1 as r;

How to combine custiom defined variables and display them as records of a table in postgres

I'm a beginner in plpgsql and working on a project which requires me to write a function that returns two variables in the form of 2 columns (res,Result). I've done a quite a bit of searching but didn't find answer for the same. The reference to my code is below
CREATE OR REPLACE FUNCTION propID(character varying)
RETURNS SETOF RECORD AS $val$
DECLARE
t_row record;
res BOOLEAN;
result character varying;
value record;
BEGIN
FOR t_row IN SELECT property_id FROM property_table WHERE ward_id::TEXT = $1 LOOP
RAISE NOTICE 'Analyzing %', t_row;
res := false; -- here i'm going to replace this value with a function whos return type is boolean in future
result := t_row.property_id;
return next result; --here i want to return 2 variables (res,result) in the form of two columns (id,value)
END LOOP;
END;
$val$
language plpgsql;
Any help on the above query would be very much appreciated.
Assuming that property_id and ward_id are integers you can achieve your goal in a simple query like this:
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = 1; -- input parameter
If you absolutely need a function, it can be an SQL function like
create or replace function prop_id(integer)
returns table (res boolean, id int) language sql
as $$
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = $1
$$;
In a plpgsql function you should use return query:
create or replace function prop_id(integer)
returns table (res boolean, id int) language plpgsql
as $$
begin
return query
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = $1;
end
$$;

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;

PGSQL error for If statement in function

I'm trying to create a function for pgsql where I need to return a boolean if an equipment exists in a lecture hall. I'm getting the following error:
"ERROR: return type mismatch in function declared to return boolean"
"DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING."
CREATE FUNCTION hasProjector(int) RETURNS boolean AS $$
DO
$do$
BEGIN
IF EXISTS(SELECT * FROM LectureRoomEquipment WHERE LectureRoomID = $1 AND EquipmentID = 1) THEN
SELECT true AS hasProjector;
ELSE
SELECT false AS hasProjector;
END IF;
END
$do$
$$ LANGUAGE SQL;
Does anyone advise me what i'm doing wrong and how I can fix this? Thank you.
You don't need plpgsql. Do it as plain SQL
create function hasprojector(int) returns boolean as $$
select exists (
select *
from lectureroomequipment
where lectureroomid = $1 and equipmentid = 1
);
$$ language sql;

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.