PostgreSql cursorfunction for unique id - postgresql

I am trying to Create a cursor on cartesian product/join as below, it gives an error
create or replace function som1() returns integer as $$
declare
rCur cursor for (select* from t1);
er route%rowtype;
begin
for er in
select route_id, location, happy from t1, t2 where exams.pid = route.pid
loop
end loop;
return 4;
end;
$$ language plpgsql;
select som1();

Related

PostgreSQL subquery with IF EXISTS in trigger function

I have a PostgreSQL trigger function like so:
CREATE FUNCTION playlists_tld_update_trigger() RETURNS TRIGGER AS
$$
BEGIN
IF EXISTS (SELECT 1 FROM "subjects" WHERE "subjects"."id" = new.subject_id) THEN
new.tld = (SELECT "subjects"."tld" FROM "subjects" WHERE "subjects"."id" = new.subject_id LIMIT 1);
END IF;
RETURN new;
END
$$
LANGUAGE plpgsql;
The trigger function will set the playlist's "tld" column to match the subject's "tld" column, but only if there exists a subject referenced by the subject_id foreign key. How do I use a subquery to combine the 2 queries into 1, or to avoid redundancy?
CREATE FUNCTION playlists_tld_update_trigger()
RETURNS TRIGGER
AS $$
DECLARE
my_tld <data_type_of_tld>;
BEGIN
SELECT subjects.tld
INTO my_tld
FROM subjects
WHERE subjects.id = new.subject_id
LIMIT 1
;
IF FOUND
THEN
new.tld = my_tld;
RETURN NEW;
ELSE
-- do something else
RETURN OLD;
END IF;
END
$$ LANGUAGE plpgsql;

Postgresql: UPDATE before INSERT function

I have problem when create function for trigger. I want to UPDATE inserted value BEFORE INSERT data to DB.
My code look like this:
CREATE OR REPLACE FUNCTION test_func()
RETURNS TRIGGER AS
$$
DECLARE cnt INTEGER;
BEGIN
cnt := COUNT(*) FROM sample_tbl WHERE id = NEW.id AND created_date = NEW.created_date;
NEW.current_order := cnt + 1; // I want to set value of sample_tbl.current_order automatically
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_trigger
BEFORE INSERT
ON test_tbl
FOR EACH ROW
EXECUTE PROCEDURE test_func();
I inserted data then IDE said:
control reached end of trigger procedure without RETURN
Where: PL/pgSQL function test_func()
The error says that you must return something from the Trigger ( either NEW or NULL )
There's no Trigger needed for this. A simple View using this select query will give you the required result
--create or replace view sample_view as
select t.id, t.created_date,
row_number() OVER ( partition by id,created_date order by id ) as current_order
FROM sample_tbl t;
This will exactly match the records if updated using a Trigger
CREATE OR REPLACE FUNCTION test_func()
RETURNS TRIGGER AS
$$
DECLARE cnt INTEGER;
BEGIN
select COUNT(*) INTO cnt FROM sample_tbl WHERE id = NEW.id
AND created_date = NEW.created_date;
NEW.current_order := cnt + 1;
RETURN NEW; --required
END
$$ LANGUAGE plpgsql;
Demo
Your trigger function is just missing RETURN NEW; statement:
CREATE OR REPLACE FUNCTION test_func()
RETURNS TRIGGER AS
$$
DECLARE cnt INTEGER;
BEGIN
cnt := COUNT(*) FROM sample_tbl WHERE id = NEW.id AND created_date = NEW.created_date;
NEW.current_order := cnt + 1;
RETURN NEW;
END
$$ LANGUAGE plpgsql;

PostgreSQL - Before Update Trigger determine which columns were updated

I have a table with many columns.
Need to find which columns value have changed.
I am using the following code. I am having a performance problem.
Can I do this with a different method?
CREATE OR REPLACE FUNCTION public.mytable()
RETURNS trigger AS $$
DECLARE
_rec record;
BEGIN
FOR _rec IN
SELECT
o.key
, o.value AS old_value
, n.value AS new_value
FROM json_each(to_json(new)) n
INNER JOIN json_each(to_json(old)) o ON o.key = n.key
LOOP
IF (_rec.old_value::text IS DISTINCT FROM _rec.new_value::text) THEN
/*
field name: _rec.key,
old values: _rec.old_value,
new value : _rec.new_value
*/
END IF;
END LOOP;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

PL/PGSQL: Store the result of a loop in a table

I want to store the result of the following loop in a table:
DO $$
DECLARE rec RECORD;
BEGIN
FOR rec IN SELECT c1 FROM t1
LOOP
SELECT foo(rec.c1);
END LOOP;
END; $$
LANGUAGE 'plpgsql';
How can I do that?
You don't need a loop for that at all. In fact you don't even need a function for that:
insert into some_table (some_column)
select foo(c1)
from t1
Or if you want to create the table based on the query:
create table_some
as
select foo(c1) as some_column
from t1;

PostgreSQL Cursor Error

I have the code:
DECLARE
cliente_cursor CURSOR FOR SELECT * FROM cliente;
cliente cliente.id_clie%TYPE;
nom cliente.nom_clie%TYPE;
BEGIN
OPEN cliente_cursor;
FETCH cliente_cursor INTO cliente, nom;
But I cannot run it. The following error appears:
ERROR: syntax error at or near "cliente"
LINE 3: cliente cliente.id_clie% TYPE;
        ^
I have the table "cliente" which has:
I want to create a cursor that shows only the content of the columns: id_clie, nom_clie of the previous table.
I have also used:
create or replace function facturas_cliente()
returns table (a int, b character varying(40))
language plpgsql as $$
declare
x cliente%rowtype ;
cliente_cursor cursor for select id_clie, nom_clie from cliente
order by id_clie;
begin
for x in cliente_cursor loop
return next x;
end loop;
end $$;
But I get the error:
ERROR: RETURN NEXT can not have parameters in a function with OUT parameters
LINE 9: return next x;
                    ^
What am I doing wrong?
First issue is strange. I tested on PostgreSQL 9.5 (but same code should to work on 9.2 and newer):
CREATE TABLE cliente(id_clie int, tel_clie varchar(15), dir_clie varchar(15));
DO $$
DECLARE
cliente_cursor CURSOR FOR SELECT * FROM cliente;
cliente cliente.id_clie%TYPE;
tel cliente.tel_clie%TYPE;
BEGIN
OPEN cliente_cursor;
END;
$$;
And it works without any issue. It looks like some mistyped error.
Second issue is clear. When function has a OUT variables or is declared as TABLE function, then RETURN NEXT has to be without expression. Returned composite value is based on actual context of OUT variables (columns declared in TABLE clause are OUT variables too). Your code should to be:
create or replace function facturas_cliente()
returns table (a int, b character varying(40))
language plpgsql as $$
declare
cliente_cursor cursor for select id_clie, nom_clie
from cliente
order by id_clie;
r record;
begin
for r in cliente_cursor -- a,b ~ OUT var declared in TABLE() clause
loop
a := r.id_clie; b := r.nom_clie;
return next; -- not: return next x;
end loop;
end $$;
This code can be reduced in PL/pgSQL two ways:
use a SQL function
create or replace function facturas_cliente()
returns table (a int, b character varying(40))
language sql as $$
select id_clie, nom_clie from cliente order by id_clie;
$$ language plpgsql;
use a RETURN QUERY statement in plpgsql:
create or replace function facturas_cliente()
returns table (a int, b character varying(40))
language sql as $$
BEGIN
RETURN QUERY SELECT id_clie, nom_clie
FROM cliente
ORDER BY id_clie;
RETURN;
END;
$$ language plpgsql;
Attention: these function can block a SQL optimizer if you use it in some complex query than trivial. Personally I don't like it. Use a view instead. It works like you need and there is no risk with optimization.
CREATE VIEW facturas_cliente
AS SELECT id_clie, nom_clie
FROM cliente
ORDER BY id_clie;