I have a slow plsql cursor where I'm updating a column in a table so I wanted to replace this cursor with a single sql statement (albeit somewhat complex ). This is what I've tried so far
with gexc_cursor as (
select *
from ( select tmp.*, rownum rn from (
select id, oib_dob as oib, opis_grupe, smjer from GRU_EXC order by ID ) tmp )
where rn between 1 and 5 ),
gd_cursor as (
select gc.id, gd.id_grupe from GRU_DOK gd, gexc_cursor gc where
gc.smjer = 'ON' AND gd.opis_grupe = gc.opis_grupe
and gd.id_vlasnika in ( select id_vlasnika from VLAS where oib_vlasnika = gc.oib )
union
select gc.id, gd.id_grupe from GRU_DOK gd, gexc_cursor gc where
gc.smjer = 'OFF' AND gd.opis_grupe = gc.opis_grupe
and gd.id_vlasnika not in ( select id_vlasnika from VLAS where oib_vlasnika = gc.oib )
)
update GRU_EXC set id_grupe = gd_cursor.id_grupe
where id = gd_cursor.id;
--ORA-00928: missing SELECT keyword
The next sql block executes but doesn't work as expected (it always updates all rows and not just the matching rows )
update GRU_EXC ge set id_grupe = (
with gexc_cursor as (
select *
from ( select tmp.*, rownum rn from (
select id, oib_dob as oib, opis_grupe, smjer from GRU_EXC order by ID ) tmp )
where rn between 1 and 5 )
select gd.id_grupe from GRU_DOK gd, gexc_cursor gc
where gc.smjer = 'ON' and gc.id = ge.id and gd.opis_grupe = gc.opis_grupe
and gd.id_vlasnika in ( select id_vlasnika from VLAS where oib_vlasnika = gc.oib )
UNION
select gd.id_grupe from GRU_DOK gd, gexc_cursor gc
where gc.smjer = 'OFF' and gc.id = ge.id and gd.opis_grupe = gc.opis_grupe
and gd.id_vlasnika not in ( select id_vlasnika from VLAS where oib_vlasnika = gc.oib )
)
Without pagination, I think your update could be done like so (minimally tested, and it seems to behave like your original update would):
MERGE INTO (SELECT *
FROM gru_exc
WHERE smjer IN ('ON', 'OFF')) tgt
USING gru_dok src
ON (tgt.opis_grupe = src.opis_grupe)
WHEN MATCHED THEN
UPDATE SET tgt.id_grupe = src.id_grupe
WHERE (tgt.smjer = 'ON' AND src.id_vlasnika IN (SELECT id_vlasnika FROM vlas WHERE (vlas.oib_vlasnika = tgt.oib_dob))
OR (tgt.smjer = 'OFF' AND src.id_vlasnika NOT IN (SELECT id_vlasnika FROM vlas WHERE vlas.oib_vlasnika = tgt.oib_dob))
AND (tgt.id_grupe != src.id_grupe OR tgt.id_grupe IS NULL);
Updating a table in chunks is, IMO, something that needs a good reason (e.g. it's a one-off update and the rollback tablespace isn't sized appropriately), otherwise I'd be pushing back on that requirement. Especially if this is something that's going to be run frequently.