Return table in function postgres - postgresql

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.

Related

Declare a Table as a variable in a stored procedure?

I am currently working a stored procedure capable of detecting continuity on a specific set of entries..
The specific set of entries is extracted from a sql query
The function takes in two input parameter, first being the table that should be investigated, and the other being the list of ids which should be evaluated.
For every Id I need to investigate every row provided by the select statement.
DROP FUNCTION IF EXISTS GapAndOverlapDetection(table_name text, entity_ids bigint[]);
create or replace function GapAndOverlapDetection ( table_name text, enteity_ids bigint[] )
returns table ( entity_id bigint, valid tsrange, causes_overlap boolean, causes_gap boolean)
as $$
declare
x bigint;
var_r record;
begin
FOREACH x in array $2
loop
EXECUTE format('select entity_id, valid from' ||table_name|| '
where entity_id = '||x||'
and registration #> now()::timestamp
order by valid ASC') INTO result;
for var_r in result
loop
end loop;
end loop ;
end
$$ language plpgsql;
select * from GapAndOverlapDetection('temp_country_registration', '{1,2,3,4}')
I currently get an error in the for statement saying
ERROR: syntax error at or near "$1"
LINE 12: for var_r in select entity_id, valid from $1
You can iterate over the result of the dynamic query directly:
create or replace function gapandoverlapdetection ( table_name text, entity_ids bigint[])
returns table (entity_id bigint, valid tsrange, causes_overlap boolean, causes_gap boolean)
as $$
declare
var_r record;
begin
for var_r in EXECUTE format('select entity_id, valid
from %I
where entity_id = any($1)
and registration > now()::timestamp
order by valid ASC', table_name)
using entity_ids
loop
... do something with var_r
-- return a row for the result
-- this does not end the function
-- it just appends this row to the result
return query
select entity_id, true, false;
end loop;
end
$$ language plpgsql;
The %I injects an identifier into a string and the $1 inside the dynamic SQL is then populated through passing the argument with the using keyword
Firstly, decide whether you want to pass the table's name or oid. If you want to identify the table by name, then the parameter should be of text type and not regclass.
Secondly, if you want the table name to change between executions then you need to execute the SQL statement dynamically with the EXECUTE statement.

POSTGRES - Query has no destination for result data with trimmed mean

I'm new at postgresql and i'm trying to make a function that will return the trimmed mean about all table data. When i try to run this query i get the error message:
ERROR: query has no destination for result data
This is the function:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
BEGIN
IF coluna = 'tempo_ciclo' THEN
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
ELSE
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo_liquido) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
END IF;
RETURN media;
END;
$$ LANGUAGE plpgsql;
You are getting this error message because you execute a query in your function, but nothing happens with the output. RETURN media doesn't actually return anything because media isn't defined, it's only the alias of the column in your query, which is unknown after the query ends.
You will either need to:
Assign the result to a variable:
DECLARE media REAL;
BEGIN
WITH (...) SELECT AVG(evento_tempo_ciclo.tempo_ciclo_liquido) INTO media ...
RETURN media;
END ...
Or return the query as the result:
RETURN QUERY AS WITH (...) SELECT ...
Or just use an SQL function rather than plpgsql:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
...
$$ LANGUAGE sql;
If you aren't 100% certain that your query will never return more than 1 result, you will need to add a LIMIT 1 to your query.

Postgres recursive function with return - on dbeaver

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$

plpgsql function with conditional statement to access column name

I'm trying to create a conditional statement in a plpgsql function what will filter out only the records I want through an if statement. I am just testing now, but here is my table structure:
CREATE TABLE addresses
(
gid serial NOT NULL,
housenum character varying(30),
prefix character varying(10),
name character varying(100),
type character varying(16)
)
Here is my function:
CREATE OR REPLACE FUNCTION "geomCheck".getAllFoo() RETURNS SETOF
addresses AS
$BODY$
DECLARE
r addresses%rowtype;
BEGIN
FOR r IN SELECT * FROM addresses
WHERE gid > 0
LOOP
if name = 'BRIE' then
RETURN NEXT r;
end if;
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
But when I go to call the function I get this error:
ERROR: column "name" does not exist
LINE 1: SELECT name = 'BRIE'
^
QUERY: SELECT name = 'BRIE'
CONTEXT: PL/pgSQL function "geomCheck".getallfoo() line 8 at IF
********** Error **********
ERROR: column "name" does not exist
SQL state: 42703
Context: PL/pgSQL function "geomCheck".getallfoo() line 8 at IF
How do I check if the name = 'BRIE' in the if statement?
You need to prefix name with r:
BEGIN
FOR r IN SELECT * FROM addresses
WHERE gid > 0
LOOP
if r.name = 'BRIE' then -- instead of "name" => "r.name"
RETURN NEXT r;
end if;
END LOOP;
RETURN;
END

Postgres 9.1 Type of SETOF record

I have dynamicly generated SELECT. I try to return result as SETOF RECORD. Sth like that:
CREATE FUNCTION test(column_name text) RETURNS SETOF RECORD AS $$
DECLARE
row RECORD;
BEGIN
FOR row IN EXECUTE 'SELECT ' || quote_ident(column_name) || ' FROM dates'
LOOP
RETURN NEXT row;
END LOOP;
RETURN;
END;
$$ LANGUAGE 'plpgsql';
When I try:
SELECT * FROM test('column1');
I get this:
ERROR: a column definition list is required for functions returning "record"
I know that column1 is integer type:
SELECT * FROM test('column1') f(a int);
result is correct, because I know that this is going to be Integer type.
When I try:
SELECT * FROM test('column1') f(a varchar);
I get error:
ERROR: wrong record type supplied in RETURN NEXT
DETAIL: Returned type integer does not match expected type character varying in column 1.
Now my question:
What to do to get rid of part of querty where I define types 'f(a int)'. It should by feasible because Postgres knowns what is returned type. I tried with IMMUTABLE options, but unsuccessfully.
You could cast the value to text inside the function, and declare that the function RETURNS SETOF text. You can also return the whole result set at once; no need to iterate explicitly.
CREATE TABLE dates (column1 int, column2 date);
INSERT INTO dates VALUES (1, date '2012-12-22'), (2, date '2013-01-01');
CREATE FUNCTION test(column_name text) RETURNS SETOF text AS $$
BEGIN
RETURN QUERY EXECUTE 'SELECT '
|| quote_ident(column_name) || '::text FROM dates';
END;
$$ LANGUAGE 'plpgsql';
Now SELECT test('column1'); yields:
test
------
1
2
(2 rows)
... and (with my locale settings) SELECT test('column2'); yields:
test
------------
2012-12-22
2013-01-01
(2 rows)
You need to specify OUT parameters corresponding to the columns you want to return.