How to do a simple array search in PL/pgSQL - postgresql

I need to know if an integer exists in an array of integers.
Here's what I have:
CREATE OR REPLACE FUNCTION mytest1 () RETURNS integer
LANGUAGE plpgsql
AS $fun$
DECLARE
testid INTEGER := 22;
testary INTEGER [] := '{1,2,3}';
BEGIN
PERFORM testid = ANY (testary);
IF FOUND THEN
RAISE NOTICE '############### found:';
END IF;
RETURN 1;
END;
$fun$
It always returns true. This should be so simple I feel ashamed asking for help. What am I doing wrong?

This is how you can resolve the issue:
CREATE OR REPLACE FUNCTION mytest1 () RETURNS integer
LANGUAGE plpgsql
AS $fun$
DECLARE
testid INTEGER := 1;
testary INTEGER [] := '{1,2,3}';
BEGIN
IF testid = ANY (testary::INTEGER[]) THEN
RETURN 1;
END IF;
RETURN 0;
END;
$fun$;
SELECT mytest1();

Can be simpler, yet:
CREATE OR REPLACE FUNCTION mytest1()
RETURNS boolean AS
$func$
DECLARE
testid int := 1;
testary int[] := '{1,2,3}';
BEGIN
RETURN (testid = ANY(testary));
END
$func$ LANGUAGE plpgsql IMMUTABLE;
The expression returns a boolean value which can be returned directly.

Related

postgresql plpgsql: not able to iterate over a array of varchar[] type

i am trying to check if a element is present in an array using plpgsql.
and i am receiving "array subscript must have integer" error while executing the function.
select test('IND') should return true and select test('ING') should return false
Below is the code
create or replace function test(country varchar)
returns varchar
language plpgsql
AS $function$
declare
results varchar;
countryarr varchar[3];
i varchar[];
begin
countryarr := array['IND','USA','MEX'];
foreach i slice 1 in array countryarr
loop
if countryarr[i]=country
then results := 'TRUE';
else
results := 'FALSE';
end if;
end loop;
return results;
end;
$function$
;
Your i is defined as a varchar[] in your code. It cannot be used as an integer.
You want something like this:
create or replace function test(country varchar)
returns varchar
language plpgsql
AS $function$
declare
countryarr varchar[3];
i text;
begin
countryarr := array['IND','USA','MEX'];
foreach i in array countryarr
loop
if i = country
then return 'TRUE';
end if;
end loop;
return 'FALSE';
end;
$function$
;
A better solution for what you are trying to achieve is:
create or replace function test(country varchar)
returns varchar
language sql
AS $function$
select case
when country = any(array['IND', 'USA', 'MEX']) then 'TRUE'
else 'FALSE'
end;
$function$;
Let your function return a boolean. Then it reduces to a single SQL statement.
create or replace function is_valid_country(country_in varchar)
returns boolean
language sql
immutable strict
AS $$
select country_in = any(array['IND', 'USA', 'MEX']) ;
$$;
with test(country) as
( values ('IND'), ('USA'), ('MEX'), ('CAN'),('UK') )
select country, is_valid_country(country) is_valid
from test;
This can be used in any subsequent sql statement. And the optimizer can in-line it.

How to initialize row datatype variables?

I would like to create a function that initialize and return the row datatype of a table as
CREATE FUNCTION get_default_table_row_object()
RETURNS mytable AS $$
DECLARE
row mytable;
BEGIN
row.field1 := 0;
row.field2 := -1;
row.record_reg_id := 1;
row.record_upd_id := 1;
row.record_reg_date := current_timestamp;
row.record_upd_date := current_timestamp;
RETURN row;
END;
$$ LANGUAGE plpgsql;
becuase my table has alot of columns and I need to create dozens of variables at several functions. I would like to use above function as
CREATE FUNCTION some_function() RETURNS VOID AS $$
DECLARE
i_obj1 mytable := get_default_table_row_object(); -- declare and initialize default values
BEGIN
-- function body
END;
$$ LANGUAGE plpgsql;
But this give me the error ERROR: default value for row or record variable is not supported. Has someway to figure it out ?
You can set it in the body instead, like so:
CREATE FUNCTION some_function() RETURNS VOID AS $$
DECLARE
i_obj1 mytable; -- declare only
BEGIN
i_obj1 := get_default_table_row_object(); -- set default values
END;
$$ LANGUAGE plpgsql;

Removing else-if-elseif.. in postgresql function

I would like to know if and there is some way to get rid code like this:
CREATE FUNCTION parent_function (json json, OUT response_status integer, OUT response json) RETURNS record
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
if <condition> then
<function_call1(json,response_status,response)>;
return;
elsif <condition> then
<function_call2(json,response_status,response)>;
return;
elsif <condition> then
<function_call3(json,response_status,response)>;
return;
end if;
END;
$$
I would like to move these conditions into separate functions where I would like based on what the function returns(there are some output parameters I need) terminate parent function without throwing exceptions and catch them in parent function?
What I would like to achive code like this:
CREATE FUNCTION parent_function (json json, OUT response_status integer, OUT response json) RETURNS record
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
<check_function1(json,response_status,response)>;
<check_function2(json,response_status,response)>;
<check_function3(json,response_status,response)>;
END;
$$
After calling message and output parameters set from function terminate further processing. Is it somehow posible?
Thanks,
Lukas
you want something like this example?
CREATE OR REPLACE FUNCTION aa_test_check1( IN test_value integer)
RETURNS TABLE( problem boolean , problemmessage text ) AS
$BODY$
begin
problem := false;
if $1 <10 then
problem := true;
problemmessage := 'integer is smaller than 10';
end if;
return next;
end;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION aa_test_check2( IN test_value integer)
RETURNS TABLE( problem boolean , problemmessage text ) AS
$BODY$
begin
problem := false;
if $1 >20 then
problem := true;
problemmessage := 'integer is greater than 20';
end if;
return next;
end;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION aa_test_check3( IN test_value integer)
RETURNS TABLE( problem boolean , problemmessage text ) AS
$BODY$
begin
problem := false;
if $1 =10 then
problem := true;
problemmessage := 'something is wrong, it cant be 10';
end if;
return next;
end;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION aa_test_main( IN test_value integer)
RETURNS TABLE( status_id integer , problemmessage text ) AS
$BODY$
declare
temp_problem boolean;
temp_problemmessage text;
begin
status_id := 0;
problemmessage := 'no problem, none at all';
select * from aa_test_check1($1)
into temp_problem, temp_problemmessage;
if temp_problem then
status_id := 1;
problemmessage := temp_problemmessage;
return next;
return;
end if;
select * from aa_test_check2($1)
into temp_problem, temp_problemmessage;
if temp_problem then
status_id := 2;
problemmessage := temp_problemmessage;
return next;
return;
end if;
select * from aa_test_check3($1)
into temp_problem, temp_problemmessage;
if temp_problem then
status_id := 3;
problemmessage := temp_problemmessage;
return next;
return;
end if;
return next;
end;
$BODY$
LANGUAGE plpgsql IMMUTABLE
COST 100
ROWS 100;
select * from aa_test_main(10)

How postgresql return a data set like the follows?

Just like the below function. I don't know how to return a set of inside parameter in postgresql?
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
while i < $1 loop
select i; -- How to write statements here?
end loop;
end;
$$ language plpgsql;
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
i := 0;
while i< $1 loop
i := i+1;
return query select i;
end loop;
end;
$$ language plpgsql;

Handling EXCEPTION and return result from function

This is my code
CREATE OR REPLACE FUNCTION test_excep (arg INTEGER) RETURNS INTEGER
AS $$
DECLARE res INTEGER;
BEGIN
res := 100 / arg;
BEGIN
EXCEPTION
WHEN division_by_zero
THEN RETURN 999;
END;
RETURN res;
END;
$$
LANGUAGE plpgsql;
That is, I need returned "999", if happened division by zero, but this: SELECT test_excep(0)
returns error: division by zero
CONTEXT: PL/pgSQL function test_excep(integer) line 4 at assignment
What is wrong in my code?
The EXCEPTION clause needs to be in the same block as the exception.
For instance:
CREATE OR REPLACE FUNCTION test_excep (arg integer)
RETURNS integer
AS
$func$
DECLARE
res INTEGER;
BEGIN
res := 100 / arg;
RETURN res;
EXCEPTION
WHEN division_by_zero
THEN RETURN 999;
END
$func$
LANGUAGE plpgsql;
Here is a correct function:
CREATE OR REPLACE FUNCTION test_excep (arg INTEGER) RETURNS INTEGER
AS $$
DECLARE res INTEGER;
BEGIN
res := 100 / arg;
RETURN res;
EXCEPTION
WHEN division_by_zero
THEN RETURN 999;
END;
$$
LANGUAGE plpgsql;
EXCEPTION part must be inside the block where the exception is, and also must be the last part of the block.