Home » SQL » Partially Rolling Back a Transaction in Oracle

Partially Rolling Back a Transaction in Oracle

You have a group of DML statements that must all complete for your transaction to be successful, but you want the capability to roll back only the most recent statements and not all statements since the beginning of the transaction.

Use the SAVEPOINT statement to create markers within the transaction. You can undo DML within the transaction to any SAVEPOINT created since the implicit or explicit beginning of the transaction. For  example, you want to adjust salaries for several employees within department 100. Employee John Chen will get a raise of $1000 per month, and all other employees in the department will get smaller raises such that the total monthly salary for the department does not exceed $60,000.

The total salary for department 100 before any updates is as follows:
select sum(salary)
from employees
where department_id = 100
;
SUM(SALARY)
-----------
56760
1 rows selected

Next, we will update Chen’s salary and create a SAVEPOINT:

update employees
set salary = salary + 1000
where employee_id = 110
;
1 rows updated

savepoint chen_salary;
savepoint chen_salary succeeded.

Next, we’ll update the rest of the salaries in department 100 and see if we’re still within the budget guidelines:

update employees
set salary = salary + 450
where department_id = 100 and employee_id != 110
;
5 rows updated

select sum(salary)
from employees
where department_id = 100
;
SUM(SALARY)
-----------
60010

1 rows selected

The total salary is over $60,000, so we need to lower the salary adjustment for all employees except for Chen. We’ll roll back the UPDATEs up to but not including the Chen salary adjustment:

rollback to savepoint chen_salary;
rollback to succeeded.

Updating the remaining employees in department 100 by a lower amount ($400 instead of $450), we find that we’re within the total salary guidelines:

update employees
set salary = salary + 400
where department_id = 100 and employee_id != 110
;
5 rows updated
select sum(salary)
from employees
where department_id = 100
;
SUM(SALARY)
----------------------
59760
1 rows selected

Finally, we’ll perform a COMMIT and look at the final salary totals:

commit;
commit succeeded.