While loop in cursor not working properly - postgresql

I tried storing the result in a varable and use coalece.
But it is not working.
do
$$
declare
v_deptno numeric := 10;
stored_empno numeric;
curempno cursor is select empno from emp e where e.deptno = v_deptno;
recempno record;
begin
open curempno;
fetch curempno
into recempno;
while found
loop
fetch curempno into recempno;
stored_empno:=recProdTest.empno;
raise info 'empno = %',coalesce(recProdTest.empno, stored_empno);
end loop;
close curempno;
end $$ language plpgsql;
Please help me.
Thanks.

Your program logic is wrong, and that won't work in Oracle either.
How many FETCH statements are executed before the first RAISE? Exactly, two: one before the loop, one in the loop.
So you are skipping the first result. The final NULL is because you don't check FOUND between FETCH and RAISE, so you report the empty result you get because the cursor is done.
Try a loop like this:
OPEN curempno;
LOOP
FETCH curempno INTO recempno;
EXIT WHEN NOT FOUND;
RAISE INFO 'empno = %', recempno.empno;
END LOOP;

Related

How many rows will be fetched from cursor with my code

I am new to plpgsql, and I am excercising cursor.
I have following simple code,
create or replace function func_cursor_2()
returns setof numeric as $$
declare
cursor1 CURSOR for select empno,ename, job from emp;
r record;
begin
open cursor1;
loop
fetch from cursor1 into r;
exit when not found;
return next r.empno;
end loop;
close cursor1;
end;
$$ language plpgsql;
select func_cursor_2()
With fetch from cursor1 into r,
It looks to me that I am fetching the result rows one by one?
Is there way to specify 100 rows for one fetch from cursor?
Why bother with a cursor at all. This can be done in 1 statement.
create or replace function func_cursor_2()
returns setof numeric
language sql
as $$
select empno
from emp
limit 100;
$$;
However, the above will not return consistent results. To generate consistent you will need to add order by empno and perhaps offset depending on your exact needs.
Note: Not Tested.

Declaring the table name in constant in Postgres Stored procedure

I have a sample stored procedure where in I have to use a table for multiple operations. I want to declare the table name as a constant and then re-use it wherever required. Below is the sample code which i wrote:
CREATE OR REPLACE FUNCTION get_data()
RETURNS void AS
$func$
DECLARE
table_name_a CONSTANT TEXT = asp.monitoring_bookmark_original;
cursor_file CURSOR FOR
select distinct filename,systemuid from table_name_a;
cursor_data CURSOR FOR
select * from table_name_a where filename = v_filename and systemuid=v_systemuid order by mindatetime, maxdatetime;
BEGIN
--open the file cursor
//logic goes here
END;
$func$
LANGUAGE plpgsql;
When I try to run this procedure I am getting error:
ERROR: missing FROM-clause entry for table "asp"
LINE 1: SELECT asp.monitoring_bookmark_original
What is wrong in this code? How do I correct this?
Well you can use dynamic SQL, but realize dynamic SQL often adds way more complexity. Good when really needed but should be avoided when possible. The following shows what would be needed for what you want to do. Is not having to type the table name for each SQL statement worth the additional trouble?
create or replace function get_data()
returns void as
$func$
declare
table_name_a constant text = 'asp.monitoring_bookmark_original';
file_cursor text = 'select distinct filename,systemuid from %i';
file_ref refcursor;
file_rec record;
data_cursor text =$stmt$select * from %i where filename = '%s' and systemuid= '%s' order by mindatetime, maxdatetime$stmt$;
data_ref refcursor;
data_rec record;
begin
--open the file cursor
open file_ref for execute format(file_cursor,table_name_a);
loop
fetch next from file_ref into file_rec;
exit when not found;
-- and extending from what the second query inplies
open data_ref for execute format(data_cursor,table_name_a,file_rec.filename,file_rec.systemid);
loop
fetch next from data_ref into data_rec;
exit when not found;
--//logic goes here
end loop;
end loop ;
end;
$func$
language plpgsql;

How to access a record's field in an Execute sentence?

I need to access a dynamic field from a dynamic table, and I have this code for doing this
Here f_field takes the name of a column from t_table dynamicly.
When t_table is declared as a record this code gets an error. But when declared as a static column fieldType it runs as expected.
The question is, How can I declared t_row for this code to run properly, or how can I achieve the same by other way. Remember that t_table and f_field are dynamic and therefore their values change.
FOR t_row IN EXECUTE 'SELECT * from ' || t_table loop
EXECUTE format('select $1.%I', f_field) USING t_row into f;
RAISE notice '%', f;
END LOOP;
if I get your task right, you dont need $1 and USING here at all, eg:
do
$$
declare
t_table text;
f text;
f_field text := 'oid';
r record;
begin
for r in (select relname from pg_class where relname = 'pg_database') loop
EXECUTE format('select %I from %I', f_field, r.relname) into f;
RAISE notice '%', f;
end loop;
end;
$$
;
mind it raises only first row out of many this way
NOTICE: 12669
DO
When I was doing my research I found out that sentences like EXECUTE... doesn't understand records structure, this was by experimenting with plpgsql because there is not doc about this. So I need to convert t_row in another kind of object that has methods to extract a value from a dynamic field, I chose json because I think it is easy to use. This is my code.
FOR t_row IN EXECUTE 'SELECT * from dd.a' loop
f_json := row_to_json(layer_row);
f := json_extract_path(f_json, f_field);
RAISE notice '%', f;
END LOOP;
It work for fine for me, but this is only a walkaround, if someone could point out why is my first code not working I will apreciate it. Thanks in advance

how to execute pgsql script in pgAdmin?

I want to execute some pgScript directly from the pgAdmin editor UI.
FOR i IN 1..10 LOOP
PRINT i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
But I always got
[ERROR ] 1.0: syntax error, unexpected character
I also tried to wrap the code with do$$...$$, but does not solve the problem.
apart from Clodoaldo Neto's Answer.You can try this also
DO
$$
BEGIN
FOR i IN 1..10 LOOP
RAISE NOTICE '%', i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
END
$$
There is no PRINT command. Use raise notice instead.
create function f()
returns void as $$
begin
FOR i IN 1..10 LOOP
raise notice '%', i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
end;
$$ language plpgsql;
http://www.postgresql.org/docs/current/static/plpgsql.html

Commit, savepoint, rollback to in PostgreSQL?

Can someone please explain to me why does COMMIT in this function returns EXCEPTION ?
DECLARE
XNar CURSOR (forDATE Varchar) IS
SELECT NARUCENO, ISPORUKA_ID FROM XDATA_NARUDZBE
WHERE TO_CHAR(XDATA_NARUDZBE.DATUM, 'DD.MM.YYYY') = forDATE;
LastDate DATE;
OutResult INTEGER;
curNAR NUMERIC;
curISP VARCHAR;
RXNar RECORD;
BEGIN
OutResult := 1;
SELECT MAX(DATUM) INTO LastDate FROM XDATA_NARUDZBE;
FOR RXNar IN XNar(TO_CHAR(LastDate, 'DD.MM.YYYY')) LOOP
IF (RXNar.NARUCENO <> 0) AND (RXNar.ISPORUKA_ID = 'R01') THEN
UPDATE NARUDZBE SET ISPORUCENO = RXNar.NARUCENO
WHERE NARUDZBE.PP_ID = RXNar.PP_ID
AND NARUDZBE.ART_ID = RXNar.ART_ID
AND NARUDZBE.ISPORUKA_ID = 'R01';
END IF;
END LOOP;
COMMIT; <--- ????
RETURN OutResult;
EXCEPTION
WHEN OTHERS THEN
OUTRESULT := 0;
RAISE;
RETURN OutResult;
END;
and why I can not use ROLLBACK TO SavePoint when EXCEPTION block exists in function?
You can't use COMMIT in a stored procedure, the entire procedure is a transaction of it's own.
You can't commit in a plpgsql stored function/procedure using plpgsql as Frank Heikens answered. You can however work around this issue by using dblink(http://www.postgresql.org/docs/9.0/interactive/contrib-dblink-connect.html) or another store procedure language such as plperl(untrusted). Check out this link where this talked about.
http://postgresql.1045698.n5.nabble.com/Re-GENERAL-Transactions-within-a-function-body-td1992810.html
The high level is you open a new connection using one of these methods and issue a separate transaction on that connection. Works for most cases not ideal because you are opening a new connection, but may work fine for most use cases.
Begin with PostgreSQL11 there is an procedure module.
Demo based on Manual.
CREATE OR REPLACE PROCEDURE insert_data_drop(_a integer, _b integer)
LANGUAGE plpgsql
AS $$
begin
INSERT INTO tbl(a) VALUES (_a);
INSERT INTO tbl(b) VALUES (_b);
Rollback;
INSERT INTO tbl(a) VALUES (_a);
end
$$;
Now CALL insert_data_drop(1, 2); will insert 1 to column a, 2 will not be saved.
However, SAVEPOINT seems not working. It will show error like:
ERROR: unsupported transaction command in PL/pgSQL
CONTEXT: PL/pgSQL function insert_data_drop(integer,integer) line 5 at SQL stateme