Push result of each query into array - plpgsql

I've created function:
CREATE FUNCTION citiesById(integer[]) RETURNS text[] AS
$$
DECLARE
element int;
result text[];
BEGIN
FOREACH element IN ARRAY $1
LOOP
WITH t1 as (SELECT city FROM cities WHERE id = element)
SELECT city FROM t1 INTO result;
END LOOP;
RETURN result;
END
$$
LANGUAGE plpgsql;
I'm trying to execute queries in a loop and insert result of each query into array to get something like ['London', 'Paris', 'Moscow']. But I'm getting an error:
Is there a correct way to do that?

CREATE FUNCTION citiesById(integer[]) RETURNS text[] AS
$$
DECLARE
element int;
result text[];
BEGIN
FOREACH element IN ARRAY $1
LOOP
result := array_append(result, (SELECT city FROM cities WHERE id = element)::text);
END LOOP;
RETURN result;
END
$$
LANGUAGE plpgsql;

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.

Dynamically access RECORD value in pl/pgsql function

Why does accessing a value of the RECORD argument like this works:
CREATE OR REPLACE FUNCTION TT_GetVal1(a RECORD)
RETURNS text AS $$
DECLARE
BEGIN
RETURN a.val1::text;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal1(foo.*)
FROM (SELECT 1 id, 'a' val1) foo;
But not like this:
CREATE OR REPLACE FUNCTION TT_GetVal2(a RECORD)
RETURNS text AS $$
DECLARE
query text;
result text;
BEGIN
query = 'SELECT ($1).val1::text';
EXECUTE query INTO result USING a;
RETURN result;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal2(foo.*)
FROM (SELECT 1 id, 'a' val1) foo;
which returns:
ERROR: could not identify column "val1" in record data type
LINE 1: SELECT ($1).val1::text
How can I dynamically access RECORD values?
The RECORD only lives inside the plpgsql scope. The values are passed to the execute but not the column names.
You can - if the record is from a table - do something like this:
create table table1 (
id integer,
val1 text
);
CREATE OR REPLACE FUNCTION TT_GetVal2(a RECORD)
RETURNS text AS $$
DECLARE
query text;
result text;
BEGIN
query = 'SELECT ($1::text::table1).val1';
EXECUTE query INTO result USING a;
RETURN result;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal2(foo)
FROM (SELECT 1 id, 'a' val1) foo;
Best regards,
Bjarni

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
$$;

How get row count from return type in postgres?

I have a function that return a table (my customer type).
How I can get row count of return object?
CREATE TYPE observer_holder AS ("CustomerName" TEXT,"CustomerFamily" TEXT)
CREATE OR REPLACE FUNCTION getItem(i_callStateText TEXT, i_maxText TEXT)
RETURNS SETOF observer_holder
LANGUAGE plpgsql
AS $$
declare
sendOffset INTEGER;
fetchRecord RECORD;
result observer_holder;
runQuery2 BOOLEAN := lower(trim(both ' ' from i_callStateText)) ='notnull' AND (position('::tsrange' in i_maxText) < 1);
query1 TEXT := '...';
query2 TEXT := '...';
BEGIN
FOR fetchRecord IN EXECUTE CASE WHEN runQuery2 THEN query2 ELSE query1 END LOOP
result."CustomerFamily" := customerRecord.family;
result."CustomerName" := customerRecord.name;
.
.
.
RETURN next result;
END LOOP;
-- my question , how get result count?
RAISE notice 'row count: %', length(result::observer_holder); >> Exception
RETURN;
END; $$;
I need result row count. Please help me.

I am trying to unnet an array in other to query the postgres DB

I am call the function but it is returning error that array value must start with "{" or dimension information using
Create or Replace Function get_post_process_info(IN v_esdt_pp character varying[])
Returns setof Record as
$$
Declare
post_processes RECORD;
esdt_value character varying;
v_sdsname character varying[];
v_dimension character varying[];
counter int := 1;
Begin
-- to loop through the array and get the values for the esdt_values
FOR esdt_value IN select * from unnest(v_esdt_pp)
LOOP
-- esdt_values as a key for the multi-dimensional arrays and also as the where clause value
SELECT distinct on ("SdsName") "SdsName" into v_sdsname from "Collection_ESDT_SDS_Def" where "ESDT" = esdt_values;
raise notice'esdt_value: %',esdt_value;
END LOOP;
Return ;
End
$$ Language plpgsql;
Select get_post_process_info(array['ab','bc]);
Your function sanitized:
CREATE OR REPLACE FUNCTION get_post_process_info(v_esdt_pp text[])
RETURNS SETOF record AS
$func$
DECLARE
esdt_value text;
v_sdsname text[];
v_dimension text[];
counter int := 1;
BEGIN
FOR esdt_value IN
SELECT * FROM unnest(v_esdt_pp) t
LOOP
SELECT distinct "SdsName" INTO v_sdsname
FROM "Collection_ESDT_SDS_Def"
WHERE "ESDT" = esdt_value;
RAISE NOTICE 'esdt_value: %', esdt_value;
END LOOP;
END
$func$ Language plpgsql;
Call:
Select get_post_process_info('{ab,bc}'::text[]);
DISTINCT instead of DISTINCT ON, missing table alias, formatting, some cruft, ...
Finally the immediate cause of the error: a missing quote in the call.
The whole shebang can possibly be replaced with a single SQL statement.
But, obviously, your function is incomplete. Nothing is returned yet. Information is missing.