Functions(procedure) - sql

I have many different queries (here is an example)
delete from dict.dct_task_type;
insert into dict.dct_task_type(id_task_type,nm_task_type)
SELECT * FROM dblink
('db',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 30 $$)
AS dct_task_type(id_task_type bigint,nm_task_type varchar);
delete from dict.dct_task_resolution;
insert into dict.dct_task_resolution (id_task_resolution,nm_task_resolution)
SELECT * FROM dblink
('db',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 32 $$)
AS dct_task_resolution(id_task_resolution bigint,nm_task_resolution varchar);
I want to do a job in time, for this I want to save the requests as procedures, how do I write them correctly?
DECLARE
variable_name datatype;
BEGIN
statements;
EXCEPTION
WHEN exception_name THEN
statements;
END;
or
CREATE OR REPLACE FUNCTION
Write an example with my values.

CREATE OR REPLACE FUNCTION dict.only_dict (
)
RETURNS void AS
$body$
BEGIN
delete from dict.dct_task_type;
insert into dict.dct_task_type(id_task_type,nm_task_type)
SELECT * FROM dblink
('ccrm_pp',
$$ select id_dict, nm_dict from dict.d_dict where kd_dict_entity = 30 $$)
AS dct_task_type(id_task_type bigint,nm_task_type varchar);
delete from dict.dct_task_resolution;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
PARALLEL UNSAFE
COST 100;
ALTER FUNCTION dict.only_dict ()
OWNER TO mb_owner;

Related

Postgres stored function return result of SELECT DISTINCT

I want to have an array of distinct integer values across my postgres table as the return value of a stored function.
The stored function currently looks like this
create or replace function get_unique_entries(id int)
returns table ("entry_id" int)
language plpgsql
as
$$
begin
return query
select distinct table.entry_id
from my_table
where x = id;
end;
$$;
When executing
select get_unique_entries(2);, I get the following error message:
structure of query does not match function result type
I tried different return types, but nothing worked for me.
Thanks in advance!
Hmm, can you give us a more complete picture of your scenario? I tried using your code and it seems to work (except I needed to replace table with my_table):
postgres=# create table my_table(x int, entry_id int, name text);
CREATE TABLE
postgres=# insert into my_table values(generate_series(1,100),generate_series(1,10),'foo');
INSERT 0 100
postgres=# create or replace function get_unique_entries(id int)
postgres-# returns table ("entry_id" int)
postgres-# language plpgsql
postgres-# as
postgres-# $$
postgres$# begin
postgres$# return query
postgres$# select distinct table.entry_id
postgres$# from my_table
postgres$# where x = id;
postgres$# end;
postgres$# $$;
ERROR: syntax error at or near "table"
LINE 8: select distinct table.entry_id
^
postgres=# create or replace function get_unique_entries(id int)
returns table ("entry_id" int)
language plpgsql
as
$$
begin
return query
select distinct my_table.entry_id
from my_table
where x = id;
end;
$$;
CREATE FUNCTION
postgres=# select get_unique_entries(2);
get_unique_entries
--------------------
2
(1 row)
postgres=#
While preparing the complete example I actually found it out myself.
As I am working with supabase, they display the datatype BIGINT as int8. I was trying to set this as return type. Setting the return type to BIGINT instead worked.
So in general check I would recommend myself and to others to check your column data types exactly.
The working example looks like this (as indicated by #richyen)
create or replace function get_unique_categories_for_platform(platformId int)
returns table ("category_fk" bigint)
language plpgsql
as
$$
begin
return query select distinct course.category_fk
from course
where platform_fk = platformId;
end;
$$;

Creating a function in postgresql dont make INSERT

cursreg returns all rows on "continguts" that not have registers on classcont. (this is ok)
But i need to insert on "classcont" the int recived on function (classificado int) for each result.
CREATE OR REPLACE FUNCTION fclassifica(clasificado int) RETURNS void AS $$
DECLARE
registre RECORD;
cursreg CURSOR FOR SELECT c.idcontingut FROM continguts as c
WHERE NOT EXISTS (SELECT * FROM classcont as ca
WHERE c.idcontingut = ca.contingut);
BEGIN
OPEN cursreg;
LOOP
FETCH FROM cursreg INTO registre;
INSERT INTO classcont (class,contingut)
VALUES (clasificado, registre.idcontingut);
RAISE NOTICE 'La classificació de ID ha estat modificada' ;
END LOOP;
CLOSE cursreg;
RETURN ;
END;
$$ LANGUAGE plpgsql;
No need for a cursor or even PL/pgSQL
CREATE OR REPLACE FUNCTION fclassifica(p_clasificado int)
RETURNS void
AS
$$
INSERT INTO classcont (class, contingut)
select p_clasificado, c.idcontingut
FROM continguts as c
WHERE NOT EXISTS (SELECT *
FROM classcont as ca
WHERE c.idcontingut = ca.contingut);
$$
language sql;

How to create a procedure that returns a set of rows from a table in postgreSQL

How do i create a Procedure that returns a set of rows from a table?
or is it even possible to return a tabular result set with procedure.
I tried adding returns setof students like you do in a function and table(id int) but it doesn't work.
SAMPLE CODE:
CREATE OR REPLACE PROCEDURE getStudents()
LANGUAGE plpgsql
AS $$
BEGIN
SELECT * FROM STUDENTS
COMMIT;
RETURN;
END;
$$;
I can call it but it says query has no destination for result data
Procedures aren't meant to return data, that's what functions are for.
You can use a plain SQL function for this, no need for PL/pgSQL:
CREATE OR REPLACE funct get_students()
returns setof student
LANGUAGE sqö
AS $$
select *
from students;
$$;
Then use it like a table:
select *
from get_students();
There is also no need for a commit.
Try to use function instead of procedure. I usually use this.
You need to create a ctype for fetching the data.
Put whatever columns you have to fetch from STUDENTS table.
Syntax is as follows:
CREATE TYPE students_data_ctype AS
(
column_1 int4,
column_2 varchar(100),
column_3 varchar(500)
)
Then create a funcction :
CREATE
OR
REPLACE
FUNCTION PUBLIC.getStudents
()
RETURNS SETOF students_data_ctype AS $BODY$ DECLARE res
students_data_ctype;
BEGIN
FOR res IN
SELECT
column_1,
column_2,
column_3
FROM
STUDENTS
LOOP RETURN NEXT res;
END LOOP;
END
; $BODY$ LANGUAGE 'plpgsql'
GO
Function call :
Select * FROM getStudents()
Taddaaa! You will get your data.

Dynamic Query Creation and Execution PostgreSQL

I have below two tables and two pl/pgsql functions.
CREATE TABLE tt1(id int, name text);
CREATE TABLE tt2(id int, name text);
INSERT INTO tt1 VALUES (1,'name1');
INSERT INTO tt1 VALUES (2,'name2');
INSERT INTO tt1 VALUES (3,'name3');
INSERT INTO tt2 VALUES (4,'name4');
INSERT INTO tt2 VALUES (5,'name5');
INSERT INTO tt2 VALUES (6,'name6');
CREATE OR REPLACE FUNCTION query_string() RETURNS TEXT AS
$BODY$
DECLARE
query1 TEXT:='';
BEGIN
query1 := 'SELECT * FROM tt1 UNION ALL SELECT * FROM tt2';
RETURN query1;
END;
$BODY$
LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION use_generated_string() RETURNS VOID AS
$BODY$
DECLARE
BEGIN
-- Need to modify here to get the result same as below query by
-- calling above function.
-- "SELECT * FROM tt1 UNION ALL SELECT * FROM tt2"
END;
$BODY$
LANGUAGE PLPGSQL;
query_string function returns the query string.
How can i modify the "use_generated_string" function so that I can get the result of the below query by calling the use_generated_string function.
SELECT * FROM tt1 UNION ALL SELECT * FROM tt2;
Can anyone help ?
If you declare the return type (and keep the called SQL fixed to that type) you can do:
CREATE OR REPLACE FUNCTION use_generated_string() RETURNS TABLE( c1 INT, c2 TEXT ) AS
$BODY$
DECLARE
BEGIN
RETURN QUERY EXECUTE query_string();
END;
$BODY$
LANGUAGE PLPGSQL;
If the return type should remain dynamic, this is a delicate problem and I suggest to start with reading Erwin Brandstetter's excellent answers.
klin's answer avoids the whole problem by using RAISE NOTICE, which is quite clever, but I'm unsure how one would go about using the results of such a call, except for manual text parsing.
Use EXECUTE:
CREATE OR REPLACE FUNCTION use_generated_string() RETURNS VOID AS
$BODY$
DECLARE
rec record;
BEGIN
FOR rec IN EXECUTE(query_string()) LOOP
RAISE NOTICE '%', rec.name;
END LOOP;
END;
$BODY$
LANGUAGE PLPGSQL;
SELECT use_generated_string();
NOTICE: name1
NOTICE: name2
NOTICE: name3
NOTICE: name4
NOTICE: name5
NOTICE: name6
use_generated_string
----------------------
(1 row)

Create function which return size of table

My code:
CREATE OR REPLACE FUNCTION sizeOfTableFunction
(
p_tableName varchar(100)
)
RETURNS integer
AS $$
DECLARE
p_tableSize integer;
BEGIN
SELECT count(*) into p_tableSize from p_tableName;
return p_tableSize;
END;
$$ LANGUAGE plpgsql STRICT;
Function has been created properly:
CREATE FUNCTION
Execute:
SELECT * FROM sizeOfTableFunction('Run');
Output - problem with executing the function?:
mydb=> SELECT * FROM sizeOfTableFunction('Run');
ERROR: relation "p_tablename" does not exist
LINE 1: SELECT count(*) from p_tableName
^
QUERY: SELECT count(*) from p_tableName
CONTEXT: PL/pgSQL function "sizeoftablefunction" line 5 at SQL statement
You need dynamic SQL for that:
CREATE OR REPLACE FUNCTION sizeOfTableFunction
(
p_tableName varchar(100)
)
RETURNS integer
AS $$
DECLARE
p_tableSize integer;
BEGIN
execute 'SELECT count(*) from '||p_tableName into p_tablesize; -- this is the difference
return p_tableSize;
END;
$$ LANGUAGE plpgsql STRICT;
To be safe, it's better to use the quote_ident function, just in case your tablename contains special characters. It also gives you some protection from SQL injection.
execute 'SELECT count(*) from '||quote_ident(p_tableName) into p_tablesize;