Postgres recursive function with return - on dbeaver - postgresql

I'm trying to create function on postgresql db using dbeaver. but when trying to save function i get error. its says "syntax error at or near "RETURN"". Maybe some one will see where is the problem.
CREATE OR REPLACE FUNCTION public.concept_children_by_id(concept_id bigint)
RETURNS TABLE(concept_description character varying, component_id bigint, father_id bigint, curr_level integer)
LANGUAGE plpgsql
AS $function$
BEGIN
WITH RECURSIVE OURCTE(component_id, father_id, curren_level) AS
(
SELECT
rel."sourceId",
rel."destinationId",
1::integer
FROM
en."sct2_Relationship_Snapshot_INT" AS rel
WHERE
rel."destinationId" = concept_id
AND
rel.active = '1'
AND
rel."typeId" = 116680003
UNION ALL
SELECT
e."sourceId",
e."destinationId",
rl.curren_level + '1'
FROM
OURCTE rl,
en."sct2_Relationship_Snapshot_INT" e
WHERE
e."destinationId" = rl."component_id"
AND
e.active = '1'
AND
e."typeId" = 116680003
)
RETURN QUERY
SELECT DISTINCT
des.term,
O.component_id,
O.father_id,
O.curren_level
FROM OURCTE O
INNER JOIN en."sct2_Description_Snapshot-en_INT" des ON (O.component_id = des."conceptId")
WHERE
des."typeId" = 900000000000003001;
ORDER BY curren_level;
RETURN;
END;
$function$

Related

Return entire row from table and columns from other tables

I'm using postgresql 14 and trying to return an entire record from a table in addition to columns from different tables. The catch is, that I don't want to write all the titles in the record. I tried working with the guide lines here [1], but I'm getting different errors. Can anyone tell me what I'm doing wrong?
CREATE OR REPLACE FUNCTION public.get_license_by_id(license_id_ integer)
RETURNS TABLE(rec tbl_licenses, template_name character varying, company_name character varying)
LANGUAGE 'plpgsql'
COST 100
VOLATILE SECURITY DEFINER PARALLEL UNSAFE
ROWS 1000
AS $BODY$
DECLARE
BEGIN
CREATE TEMPORARY TABLE tempTable AS (
SELECT
(rec).*, B.company_name, C.template_name
-- Tried using A instead of (rec).* with error: column "a" has pseudo-type record
FROM
(
(SELECT * FROM tbl_licenses) A
LEFT JOIN
(SELECT * FROM tbl_customers) B on A.customer_id = B.customer_id
LEFT JOIN
(SELECT * FROM tbl_templates) C on A.template_id = C.template_id
)
);
UPDATE tempTable
SET license = '1'
WHERE tempTable.license IS NOT NULL;
RETURN QUERY (
SELECT * FROM tempTable
);
DROP TABLE tempTable;
RETURN;
END;
$BODY$;
I'm calling the function like SELECT rec FROM get_license_by_id(1);
but getting:
ERROR: structure of query does not match function result type
DETAIL: Returned type integer does not match expected type tbl_licenses in column 1.
You need to cast the A alias to the correct record type. However the nested derived tables are not necessary for the other tables. If you use a coalesce() for the license column in the SELECT, then you get get rid of the inefficient creation and update of the temp table as well.
CREATE OR REPLACE FUNCTION get_license_by_id(license_id_ integer)
RETURNS TABLE(rec tbl_licenses, template_name character varying, company_name character varying)
LANGUAGE sql
STABLE
AS $BODY$
SELECT a::tbl_licenses, -- this is important
B.company_name, C.template_name
FROM (
select license_id, customer_id, ... other columns ...,
coalesce(license, '1') as license -- makes the temp table unnecessary
from tbl_licenses A
) a
LEFT JOIN tbl_customers B on A.customer_id = B.customer_id
LEFT JOIN tbl_templates C on A.template_id = C.template_id
where a.license_id = license_id_;
$BODY$
;

PL/pgSQL: structure of query does not match function result type

I have a table
create table abac_object (
inbound abac_attribute,
outbound abac_attribute,
created_at timestamptz not null default now(),
primary key (inbound, outbound)
);
abac_attribute is my custom type that is defined like
create type abac_attribute as (
value text,
key text,
namespace_id uuid
);
I try to create a number of functions that work over the table
create function abac_object_list_1(_attr abac_attribute)
returns setof abac_object as $$
select *
from abac_object
where outbound = _attr
$$ language sql stable;
create function abac_object_list_2(_attr1 abac_attribute, _attr2 abac_attribute)
returns setof abac_object as $$
select t1.*
from abac_object as t1
inner join abac_object as t2 on t1.inbound = t2.inbound
where
t1.outbound = _attr1
and t2.outbound = _attr2
$$ language sql stable;
create function abac_object_list_3(_attr1 abac_attribute, _attr2 abac_attribute, _attr3 abac_attribute)
returns setof abac_object as $$
select t1.*
from abac_object as t1
inner join abac_object as t2 on t1.inbound = t2.inbound
inner join abac_object as t3 on t1.inbound = t3.inbound
where
t1.outbound = _attr1
and t2.outbound = _attr2
and t3.outbound = _attr3
$$ language sql stable;
create function abac_object_list(_attrs abac_attribute[], _offset integer, _limit integer)
returns setof abac_attribute as $$
begin
case array_length(_attrs, 1)
when 1 then return query
select t.inbound
from abac_object_list_1(_attrs[1]) as t
order by t.created_at
offset _offset
limit _limit;
when 2 then return query
select t.inbound
from abac_object_list_2(_attrs[1], _attrs[2]) as t
order by t.created_at
offset _offset
limit _limit;
when 3 then return query
select t.inbound
from abac_object_list_3(_attrs[1], _attrs[2], _attrs[3]) as t
order by t.created_at
offset _offset
limit _limit;
else raise exception 'bad argument' using detail = 'array length should be less or equal to 3';
end case;
end
$$ language plpgsql stable;
abac_object_list_1 works fine
select *
from abac_object_list_1(('apple', 'type', '00000000-0000-1000-a000-000000000010') ::abac_attribute);
However with abac_object_list I get the following error
select *
from abac_object_list(array [('apple', 'type', '00000000-0000-1000-a000-000000000010')] :: abac_attribute[], 0, 100);
[42804] ERROR: structure of query does not match function result type Detail: Returned type abac_attribute does not match expected type text in column 1. Where: PL/pgSQL function abac_object_list(abac_attribute[],integer,integer) line 4 at RETURN QUERY
I can't understand where text type comes from.
These functions worked before but then I added created_at column to be able to add explicit ORDER BY clause. And now I can't rewrite functions correctly.
Also maybe there is a better (or more idiomatic) way to define these function.
Could you please help me to figure it out?
Thank you.
P. S.
Well, it seems to work if I write
return query select (t.inbound).*
But I am not sure if it is a right approach.
Also I wonder what is better to use return table or return setof.

Return table in function postgres

When trying to return table in postgres, this my query:
CREATE OR REPLACE FUNCTION list_log_approval(IN p_create_code INTEGER,IN p_update_code INTEGER) RETURNS
TABLE(processcode integer, processname VARCHAR,id BIGINT, pleader CHARACTER VARYING,activity VARCHAR,date_plead timestamp)
LANGUAGE plpgsql AS $$
BEGIN
IF NOT EXISTS( SELECT * FROM log_approval WHERE processcode = $1 and status = 'A' or status = 'D')AND NOT EXISTS(SELECT * FROM log_approval WHERE processcode = $2 and status = 'A' or status = 'D') THEN
RETURN QUERY SELECT * from vw_list_appv;
END IF;
RETURN;
END $$;
-- i call like this
select * from list_log_approval(1070,1072)
I get the following error:
[Err] ERROR: column reference "processcode" is ambiguous
LINE 3: processcode**
why is it ambiguous?
processcode is used both as function parameter and as table column.
The best thing is to use function parameters with a different name, like p_processcode.
But you can also disambiguate by qualifying the name: log_approval.processcode for the column and list_log_approval.processcode for the function parameter.

Select statement within function blank results

I'm using Postgresql and trying to have a select statement in a function to call out. At the moment the call gives me zero results
CREATE OR REPLACE FUNCTION f_all_male_borrowers
(
OUT p_given_names varchar(60),
OUT p_family_name varchar(60),
OUT p_gender_code integer
)
RETURNS SETOF record as $body$
declare body text;
BEGIN
SELECT into p_given_names,p_family_name, p_gender_code
borrower.given_names, borrower.family_name, gender.gender_code
FROM BORROWER
INNER join gender on borrower.gender_code=gender.gender_code
WHERE borrower.gender_code = '1';
RETURN ;
END;
$body$ LANGUAGE plpgsql;
Call to function:
select * from f_all_male_borrowers()
What is missing, or what am I doing wrong here?
Thank you
CREATE OR REPLACE FUNCTION f_all_male_borrowers
(
OUT p_given_names varchar(60),
OUT p_family_name varchar(60),
OUT p_gender_code integer
)
RETURNS SETOF record as
$body$
SELECT into p_given_names,p_family_name, p_gender_code
borrower.given_names, borrower.family_name, gender.gender_code
FROM BORROWER
INNER join gender on borrower.gender_code=gender.gender_code
WHERE borrower.gender_code = '1';
$body$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION f_all_male_borrowers()
OWNER TO postgres;
Try this and then call :
select * from f_all_male_borrowers();
Before doing that you need to check whether your query have result or not !!
After creating function then:
Got to Functions->Right click your function(ie,f_all_male_borrowers())-> Scripts->Select Script ->Then run it.
If it returns result then your procedure is correct.

Greenplum/Postgres 8 function dynamic result set?

I need to write a function that returns a table with unknown number of columns.
If i receive 'None' in column input parameter then that column shouldn't be included in the output. In postgres 9+ there is a solution for this problem.
something like below:
CREATE OR REPLACE FUNCTION data_of(id integer,col1 varchar,col2 varchar, col3 varchar)
RETURNS TABLE (count_rec, dimensions text[] ) AS
$func$
DECLARE
_dimensions text := 'col1, col2, col3'; -- If i receive 'None' in input param then i exclude that from column list
BEGIN
RETURN QUERY EXECUTE format('
SELECT count(*) as count_rec,
string_to_array($1) -- AS dimensions
FROM x
WHERE id = $2'
, _dimensions)
USING _dimensions , _id;
END
$func$ LANGUAGE plpgsql;
But in Greenplum (Postgres 8.2) i could not find any. Is there any similar solution?
thanks
You have 2 options to do it: use set-returning function returning "record" or returning your custom type.
First option:
create table test (a int, b int, c int, d varchar, e varchar, f varchar);
insert into test select id, id*2, id*3, (id*4)::varchar, (id*4)::varchar, (id*4)::varchar from generate_series(1,10) id;
create or replace function test_func(column_list varchar[]) returns setof record as $BODY$
declare
r record;
begin
for r in execute 'select ' || array_to_string(column_list, ',') || ' from test' loop
return next r;
end loop;
return;
end;
$BODY$
language plpgsql
volatile;
select * from test_func(array['a','c','e']) as f(a int, c int, e varchar);
Second option:
create table test (a int, b int, c int, d varchar, e varchar, f varchar);
insert into test select id, id*2, id*3, (id*4)::varchar, (id*4)::varchar, (id*4)::varchar from generate_series(1,10) id;
create type testtype as (
a int,
c int,
e varchar
);
create or replace function test_func() returns setof testtype as $BODY$
declare
r testtype;
begin
for r in execute 'select a,c,e from test' loop
return next r;
end loop;
return;
end;
$BODY$
language plpgsql
volatile;
select * from test_func();
But I'm 99% sure you're trying to do something wrong. In Greenplum the result of function execution cannot be used as a "table" in join conditions, because the function executes on the master. You even won't be able to create a table out of the last query returning the data from your function because of this limitation
In short, this is not a recommended way to work with data in Greenplum