Cursor not found - postgresql

i have created procedure, inside used cursor to update the some data, while calling the procedure it's getting the error.
create or REPLACE PROCEDURE bal_upd(p_id int) as
$$
DECLARE rc record;
----- cursor
bal_upd1 CURSOR (p_id int)
for
select * from tbal where custid = p_id;
begin
open bal_upd1 (p_id);
loop
FETCH bal_upd1 into rc;
exit when not found;
update t_trans set balance = balance + rc.trans;
COMMIT;
end loop;
close bal_upd1;
end;
$$ LANGUAGE plpgsql;
call bal_upd(1)
ERROR: cursor "bal_upd1" does not exist
CONTEXT: PL/pgSQL function bal_upd(integer) line 12 at FETCH
SQL state: 34000
create or REPLACE PROCEDURE bal_upd(p_id int) as
$$
DECLARE rc record;
----- cursor
bal_upd1 CURSOR (p_id int)
for
select * from tbal where custid = p_id;
begin
open bal_upd1 (p_id);
loop
FETCH bal_upd1 into rc;
exit when not found;
update t_trans set balance = balance + rc.trans;
COMMIT;
end loop;
close bal_upd1;
end;
$$ LANGUAGE plpgsql;
call bal_upd(1)
ERROR: cursor "bal_upd1" does not exist
CONTEXT: PL/pgSQL function bal_upd(integer) line 12 at FETCH
SQL state: 34000

You don't need a function or a loop for that:
UPDATE t_trans
SET balance = t_trans.balance + t.trans
FROM (SELECT sum(trans) AS trans
FROM tbal
GROUP BY custid) AS t
WHERE t_trans.custid = t.custid;

I tried, failed. I just found just use for loop (implicit cursor) is far more simple.
BEGIN;
CREATE temp TABLE tbal (
custid bigint
, trans numeric
);
INSERT INTO tbal VALUES (1 , 1);
INSERT INTO tbal VALUES (1 , 2);
CREATE temp TABLE t_trans (
custid bigint
, balance numeric
);
INSERT INTO t_trans VALUES (1 , 10);
COMMIT;
CREATE OR REPLACE PROCEDURE bal_upd (bigint)
AS $func$
DECLARE
rc record;
BEGIN
FOR rc IN
SELECT
*
FROM
tbal
WHERE
custid = $1 LOOP
RAISE NOTICE 'custid: %, trans: % ' , rc.custid , rc.trans;
UPDATE
t_trans ta
SET
balance = balance + (rc.trans)
WHERE
ta.custid = (rc.custid);
END LOOP;
END;
$func$
LANGUAGE plpgsql;
Then call it. CALL bal_upd(1);

Related

postgres: cursor "xxx" does not exist

I'm new in pspgsql and I'm unable to understand why the cursor does not exists on fetch. Can anyone tell me what is wrong, please?
CREATE OR REPLACE PROCEDURE public.import_candles(
IN in_source varchar(16),
IN in_timeframe varchar(3),
IN in_symbol varchar(8),
IN in_bulk integer DEFAULT 10000)
LANGUAGE 'plpgsql'
AS $BODY$
declare
bulkCounter int;
rec_input record;
cur_input cursor(psource varchar(16), ptimeframe varchar(3), psymbol varchar(8)) for
select distinct time, open, high, low, close, volume
from candlesticks_input
where source = psource and timeframe = ptimeframe and symbol = psymbol;
begin
bulkCounter := 0;
open cur_input(in_source, in_timeframe, in_symbol);
loop
fetch cur_input into rec_input;
exit when not found;
-- more code here ...
bulkCounter = bulkCounter + 1;
if MOD(bulkCounter,in_bulk) = 0 then
commit;
end if;
end loop;
close cur_input;
commit;
end
$BODY$;
When I call this function:
call import_candles('MY_SOURCE', 'H1', 'EURUSD');
I got the error:
ERROR: cursor "cur_input" does not exist
CONTEXT: PL/pgSQL function import_candles(character varying,character varying,character varying,integer) line 14 at FETCH
SQL state: 34000
Try:
open cur_input(psource:=in_source, ptimeframe:=in_timeframe, psymbol:=in_symbol);
like shown here

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;

I tried to execute a query and gave me an error and i can't understand why?

DROP FUNCTION IF EXISTS top_5(customers.customerid%TYPE, products.prod_id%TYPE, orderlines.quantity%TYPE) CASCADE;
CREATE OR REPLACE FUNCTION top_5(c_id customers.customerid%TYPE, p_id products.prod_id%TYPE, quant orderlines.quantity%TYPE)
RETURNS orders.orderid%TYPE AS $$
DECLARE
top_prod CURSOR IS
SELECT inv.prod_id
FROM inventory AS inv, products AS prod
WHERE inv.prod_id=prod.prod_id
ORDER BY inv.quan_in_stock desc, inv.sales
limit 5;
ord_id orders.orderid%TYPE;
ord_date orders.orderdate%TYPE:= current_date;
ordln_id orderlines.orderlineid%TYPE:=1;
BEGIN
SELECT nova_orderid() INTO ord_id;
INSERT INTO orders(orderid, orderdate,customerid,netamount,tax,totalamount) VALUES(ord_id,ord_date,c_id,0,0,0);
PERFORM compra(c_id, p_id, 1::smallint, ord_id, ordln_id, ord_date);
IF (p_id = top_prod) THEN
UPDATE orders
SET totalamount = totalamount - (totalamount*0.2)
WHERE ord_id = (SELECT MAX(ord_id) FROM orders);
END IF;
END;
$$ LANGUAGE plpgsql;
I have the following code and when i try to execute this
SELECT top_5(1,1,'2');
i have this error
ERROR: operator does not exist: integer = refcursor
LINE 1: SELECT (p_id = top_prod)
You need to get the 'prod_id' value from the cursor 'top_prod'.
You cannot compare two types.
Try this,
DECLARE
top_prod_id top_prod%ROWTYPE;
BEGIN
OPEN top_prod;
LOOP
FETCH top_prod INTO top_prod_id;
EXIT WHEN top_prod %NOTFOUND;
IF (p_id = top_prod_id) THEN
UPDATE orders
SET totalamount = totalamount - (totalamount*0.2)
WHERE ord_id = (SELECT MAX(ord_id) FROM orders);
END IF;
END LOOP;
CLOSE top_prod;
END;

How to know the date of modification of an SP?

Is it possible to know the date of modification and / or creation of an SP in PostgreSQL 9.4?
I need to identify them to upload them next Deploy.-
PostgreSQL has not this functionality. You can create own table and update it from event triggers.
create table updates(proc regprocedure primary key, t timestamp);
create or replace function event_trigger_for_ddl_command_end()
returns event_trigger as $$
declare obj record;
begin
for obj in select * from pg_event_trigger_ddl_commands()
loop
if obj.classid = 'pg_proc'::regclass then
insert into updates values(obj.objid, current_timestamp)
on conflict (proc) do update set t = current_timestamp
where updates.proc = excluded.proc;
end if;
end loop;
end;
$$ language plpgsql;
create event trigger trigger_for_ddl_command_end
on ddl_command_end
execute procedure event_trigger_for_ddl_command_end();
create or replace function fx(a int) returns int as $$ select 1 $$ language sql;
postgres=# select * from updates ;
+-------------+----------------------------+
| proc | t |
+-------------+----------------------------+
| fx(integer) | 2017-11-22 14:21:11.367036 |
+-------------+----------------------------+
(1 row)
-- alternative code without INSERT ON CONFLICT
create or replace function event_trigger_for_ddl_command_end()
returns event_trigger as $$
declare obj record;
begin
for obj in select * from pg_event_trigger_ddl_commands()
loop
if obj.classid = 'pg_proc'::regclass then
begin
update updates set t = current_timestamp
where proc = obj.objid;
if not found then
begin
insert into updates values(obj.objid, current_timestamp);
exception when unique_violation then
update updates set t = current_timestamp
where proc = obj.objid;
end;
end if;
end if;
end loop;
end;
$$ language plpgsql;

Syntax error while creating function in postgresql

I got a syntax error while creating a procedure in postgresql.Here I attached my code.I got a error syntax error near "Continue"
create function patient_form_values() RETURNS void AS
$$ begin
DECLARE columnName varchar(200) ;
DECLARE done boolean default true;
DECLARE CONTINUE handler for not found set done = false;
DECLARE cur1 cursor for select distinct COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'currentdiagnosis';
open cur1;
read_loop : loop
fetch from cur1 into columnName;
if done then leave read_loop;
end if;
set #insertValues := concat('INSERT INTO patient_form_temp(patient_id, form_template_id, creator_id, created_date)
SELECT c.patient_id as patient_id, 41 AS form_template_id, 2 AS creator_id, c.created_date AS created_date
FROM currentdiagnosis c
WHERE c.', columnName,' IS NOT NULL GROUP BY c.patient_id, c.created_date');
select #insertValues;
prepare stmt from #insertValues;
execute stmt;
end loop;
close cur1;
end ;
$$ LANGUAGE plpgsql
You are trying to use a MySQL (or other DB?) function in PostgreSQL. There is no concept of CONTINUE HANDLER in PostgreSQL, so you have to convert the function into PostgreSQL format.
drop FUNCTION if exists migratePartnerAdvertiser();
CREATE OR REPLACE FUNCTION migratePartnerAdvertiser() RETURNS int4 AS '
DECLARE r RECORD;
BEGIN
FOR r IN select distinct COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = ''currentdiagnosis'' and table_schema=''public'' LOOP
EXECUTE concat(''INSERT INTO patient_form_temp(patient_id, form_template_id, creator_id, created_date) SELECT c.patient_id as patient_id, 41 AS form_template_id, 2 AS creator_id, c.reg_date AS created_date FROM currentdiagnosis c WHERE c.'' , r.column_name , '' IS NOT NULL GROUP BY c.patient_id, c.reg_date'');
END LOOP;
return 1;
END;
' LANGUAGE plpgsql;