'multiple update pgsql using cursor

this code not error but nothing data change please help me. I want to multiple update quantity from some stock table

drop FUNCTION SP_PROSES_STOCK(noresep bigint, p_post_cd varchar);
CREATE or replace FUNCTION SP_PROSES_STOCK(noresep bigint, p_post_cd varchar)
RETURNS void
LANGUAGE plpgsql
as $function$
DECLARE cursorData refcursor;
    v_item_cd varchar;
    v_quantity numeric;

begin

open cursorData FOR
select A.item_cd, A.quantity from trx_medical_resep B
inner join trx_resep_data A on A.medical_resep_seqno = B.medical_resep_seqno
where B.medical_resep_seqno = noresep; 
fetch next from cursorData into v_item_cd,v_quantity;
while (found)
loop
    update inv_pos_item set quantity = quantity - v_quantity 
    where item_cd = v_item_cd and pos_cd = p_post_cd;
end loop;
close cursorData;

END 
$function$


Solution 1:[1]

I mopdify your function to make it shorter and use FOR. Also I add RAISE NOTICE for debugging. Can you try it:

CREATE or replace FUNCTION SP_PROSES_STOCK(noresep bigint, p_post_cd varchar)
RETURNS void
LANGUAGE plpgsql
as $function$
DECLARE v_cursor record;

BEGIN

   FOR v_cursor IN
       SELECT A.item_cd,
              A.quantity
         FROM trx_medical_resep B
         JOIN trx_resep_data A ON A.medical_resep_seqno = B.medical_resep_seqno
        WHERE B.medical_resep_seqno = noresep
   LOOP
       RAISE NOTICE 'Changes for %', v_curosr; 
       UPDATE inv_pos_item
           SET quantity = quantity - v_cursor.quantity 
         WHERE item_cd = v_cursor.item_cd
           AND pos_cd = p_post_cd;
   END LOOP;
END 
$function$

After debugging you can remove RAISE NOTICE.

Solution 2:[2]

You don't need a loop for this. A single UPDATE statement will be a lot faster:

CREATE or replace FUNCTION SP_PROSES_STOCK(noresep bigint, p_post_cd varchar)
  RETURNS void
as 
$function$
begin

  update inv_pos_item 
     set quantity = quantity - v.quantity 
  from (
    select A.item_cd, A.quantity 
    from trx_medical_resep B
      join trx_resep_data A on A.medical_resep_seqno = B.medical_resep_seqno
    where B.medical_resep_seqno = noresep
  ) v
  where item_cd = v.item_cd and pos_cd = p_post_cd;

END;
$function$
LANGUAGE plpgsql;

Solution 3:[3]

There are scenarios where a cursor is needed. For example lets say you are updating 10 million rows and an exception is thrown at the 6th million record the the update will fail and then it will rollback all of the rows that were updated prior to the failure. If a cursor is used it will be slower but you will have greater control over the process and be able to bypass the error and continue with the posting of the updates. But then again your milage may vary...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 a_horse_with_no_name
Solution 3 Raul