OraQA

Oracle Question and Answer

  • Do you have a solution to a problem? Do you have an unanswered question? Login and share it with the Oracle community. More...

Oracle News


Entries RSS feed

Comments RSS feed

How to rollback committed data based on a group ID in SQL

December 4th, 2007 By Frank Zhou

The following SQL pattern can be used to rollback committed data based on the group ID in a SQL.
(The restriction of this pattern is that the primary key (id) should not be modified)

create table flash_tab as
select 10 groupId, 1 id , 'A' name from dual
union all
select 10 groupId, 2 id , 'B' name from dual
union all
select 10 groupId, 3 id , 'C' name from dual
union all
select 10 groupId, 4 id , 'D' name from dual
union all
select 20 groupId, 5 id , 'E' name from dual
union all
select 20 groupId, 6 id , 'F' name from dual
union all
select 20 groupId, 7 id , 'group_20_testing_row_data' name from dual;

ALTER TABLE flash_tab ADD (CONSTRAINT pk_id PRIMARY KEY (id));

select * from flash_tab order by groupId, id;

   GROUPID         ID NAME
---------- ---------- -------------------------
        10          1 A
        10          2 B
        10          3 C
        10          4 D ---**All group 10 data will be rollback later.
        20          5 E
        20          6 F
        20          7 group_20_testing_row_data

7 rows selected.
update flash_tab set name = 'group_name_changed' where id = 1;
delete flash_tab where id = 2;
update flash_tab set groupId= 30,name ='group_num_changed'where id = 3;
update flash_tab set groupId= 40, name ='group_num_name_changed' where id = 4;
insert into flash_tab(groupId, id, name ) values (10, 99, 'group_10_newRow');
delete flash_tab where id = 5;
update flash_tab set name = 'No_RollBack_group_20' where id = 6;
insert into flash_tab ( groupId, id, name ) values (20, 28, 'group_20_newRow');

SQL> commit;

select * from flash_tab order by groupId;

   GROUPID         ID NAME
---------- ---------- -------------------------
        10          1 group_name_changed
        10         99 group_10_newRow
        20          6 No_RollBack_group_20
        20          7 group_20_testing_row_data
        20         28 group_20_newRow
        30          3 group_num_changed
        40          4 group_num_name_changed

7 rows selected.
variable groupId_input  number
exec :groupId_input  := 10;

—————————-SQL Solution—————–

MERGE INTO flash_tab tgt
USING (SELECT src.groupId, src.id, src.name,
              tgt.groupId AS tgt_groupId,
              tgt.id AS tgt_id, tgt.name AS tgt_name
        FROM flash_tab AS OF
             TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' SECOND) src
        FULL OUTER JOIN flash_tab tgt ON (src.id = tgt.id)
      ) src
ON (src.tgt_id = tgt.id)
WHEN MATCHED THEN
UPDATE
SET tgt.groupId= src.groupId, tgt.name = src.name
WHERE (LNNVL(tgt.groupId = src.groupId) OR LNNVL(tgt.name = src.name))
  AND (NVL(src.groupId, tgt.groupId) = :groupId_input )
DELETE
WHERE LNNVL(src.id = tgt.id)
  AND tgt.groupId IS NULL AND tgt.name IS NULL
WHEN NOT MATCHED THEN
  INSERT (tgt.groupId, tgt.id, tgt.name)
  VALUES (src.groupId, src.id, src.name)
WHERE src.groupId= :groupId_input;

SQL> commit;

select * from flash_tab order by groupId, id;

  GROUPID         ID NAME
---------- ---------- -------------------------
        10          1 A
        10          2 B
        10          3 C
        10          4 D ---** Roll back only the group 10 data **------
        20          6 No_RollBack_group_20
        20          7 group_20_testing_row_data
        20         28 group_20_newRow

Leave a Reply

You must be logged in to post a comment.

RSS feed for comments on this question