Creating a function in postgresql dont make INSERT - sql

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;

Related

Functions(procedure)

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;

Correct SQL table alias syntax in trigger with if statement

So basically I'm trying to create a trigger that will update another table if an insert or update is located less than 1 meter of distance of an existing one.
It does not allow me to insert anything because the FROM clause is missing on the if statement and I'm not sure how to call it properly.
I got the following
CREATE TRIGGER access_node_aiu
AFTER INSERT OR UPDATE
ON schemab.table
FOR EACH ROW
EXECUTE PROCEDURE schemab.trigegr();
CREATE OR REPLACE FUNCTION schemab.trigger()
RETURNS trigger AS
$BODY$
BEGIN
if st_distance(new.geom, a.geom) < 1 then
INSERT INTO schemab.overlap
SELECT nextval('schemab.overlap_id_seq'::regclass), a.node_id, new.node_id, a.date, now(), st_distance(a.geom, new.geom), new.geom
FROM schemab.table a;
end if;
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
How to do this in postgresql?
Change IF into WHERE
CREATE OR REPLACE FUNCTION schemab.trigger()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO schemab.overlap
SELECT nextval('schemab.overlap_id_seq'::regclass), a.node_id, new.node_id, a.date, now(), st_distance(a.geom, new.geom), new.geom
FROM schemab.table a
WHERE st_distance(new.geom, a.geom) < 1;
RETURN new;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

return %ROWTYPE from function PostgreSQL

I've tried to do following:
CREATE TABLE mytable(id integer NOT NULL,
name character varying,
CONSTRAINT pk_table PRIMARY KEY (id));
CREATE OR REPLACE FUNCTION fnmytable(inout p_rec mytable)
RETURNS mytable AS
$BODY$
declare
begin
p_rec.id := 1;--sequence
INSERT INTO mytable(id,
name)
VALUES (p_rec.id,
p_rec.name);
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
do
$$
declare
r_rec mytable%rowtype;
begin
r_rec.name := 'Jorge';
perform fnmytable(r_rec);
raise notice 'OUT ID: %', r_rec.id;
end;
$$
NOTICE: OUT ID: "NULL"
How to return the value of the sequence?
You have to use
SELECT * FROM fnmytable(r_rec) INTO r_rec;
I know that INOUT seems to suggest that the input parameter gets modified, but that is not the case. (INOUT p_rec mytable) is a shorthand for (p_rec mytable) RETURNS mytable.
Put differently, functions in PostgreSQL are always pass by value and not pass by reference.
Please try this
CREATE OR REPLACE FUNCTION fnmytable(inout p_rec mytable) AS
--EDITED HERE
$BODY$
declare
begin
p_rec.id := 1;--sequence
INSERT INTO mytable(id,
name)
VALUES (p_rec.id,
p_rec.name);
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
calling the function
do
$$
declare
r_rec mytable%rowtype;
begin
r_rec.name := 'Jorge';
select * from fnmytable(r_rec) into r_rec; --EDITED HERE
raise notice 'OUT ID: %', r_rec.id;
end;
$$

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)

cannot pass dynamic query to sql-function

I cannot seem to find a way to pass my query as a parameter to my sql-function. My problem is table 'my_employees1' could be dynamic.
DROP FUNCTION function_test(text);
CREATE OR REPLACE FUNCTION function_test(text) RETURNS bigint AS '
DECLARE ret bigint;
BEGIN
SELECT count(mt.id) INTO ret
FROM mytable as mt
WHERE mt.location_id = 29671
--and mt.employee_id in (SELECT id from my_employees1);
--and mt.employee_id in ($1);
$1;
RETURN ret;
END;
' LANGUAGE plpgsql;
select function_test('and mt.employee_id in (SELECT id from my_employees1)');
select function_test('SELECT id from my_employees1');
It must be dynamically built:
DROP FUNCTION function_test(text);
CREATE OR REPLACE FUNCTION function_test(text) RETURNS bigint AS $$
DECLARE
ret bigint;
BEGIN
execute(format($q$
SELECT count(mt.id) INTO ret
FROM mytable as mt
WHERE mt.location_id = 29671
%s; $q$, $1)
);
RETURN ret;
END;
$$ LANGUAGE plpgsql;
The $$ and $q$ are dollar quotes. They can be nested as long as the inner identifier is different. In addition to the obvious advantages of permitting the use of unquoted quotes and being nestable it also let the syntax highlighting do its work.