.....
The problem is another long running transaction might have consumed sequence with lower numbers but has not commited when batch was run, thus those change_ids will never be exported
.....in Session#1 - we do this
demo@ORA26AI> create table oltp
2 as
3 select all_users.*, sysdate last_updated
4 from all_users
5 where rownum <= 5;
Table created.
demo@ORA26AI>
demo@ORA26AI> create or replace trigger last_updated_trigger
2 before insert or update on oltp for each row
3 begin
4 :new.last_updated := sysdate;
5 end;
6 /
Trigger created.
demo@ORA26AI> exec dbms_session.sleep(5);
PL/SQL procedure successfully completed.
demo@ORA26AI> update oltp set username = 'ABC' where rownum = 1;
1 row updated.
demo@ORA26AI>
in session#2 - we do this
demo@ORA26AI> column FIRST_REFRESH new_val FIRST_REFRESH
demo@ORA26AI> select sysdate FIRST_refresh from dual;
FIRST_REFRESH
------------------
12-mar-26 12:01:35
demo@ORA26AI> create table copy as select * from oltp;
Table created.
demo@ORA26AI> column NEXT_REFRESH new_val NEXT_REFRESH
demo@ORA26AI> select sysdate NEXT_refresh from dual;
NEXT_REFRESH
------------------
12-mar-26 12:01:49
demo@ORA26AI> merge into copy
2 using
3 (select * from oltp
4 where last_updated >= to_date('&FIRST_REFRESH') ) OLTP
5 on ( copy.user_id = oltp.user_id )
6 when matched then
7 update set username = oltp.username, created = oltp.created,
8 last_updated = oltp.last_updated
9 when not matched then
10 insert (username,user_id,created,last_updated) values
11 (oltp.username, oltp.user_id, oltp.created, oltp.last_updated );
old 4: where last_updated >= to_date('&FIRST_REFRESH') ) OLTP
new 4: where last_updated >= to_date('12-mar-26 12:01:35') ) OLTP
0 rows merged.
demo@ORA26AI> select 'OLTP', oltp.* from oltp minus select 'OLTP', copy.* from copy
2 union all
3 select 'COPY', copy.* from copy minus select 'COPY', oltp.* from oltp;
no rows selected
demo@ORA26AI> /* these tables are the same now, right -- nothing could be 'wrong'
demo@ORA26AI> but wait.... goto that other session and type 'commit' */
demo@ORA26AI>
once we do commit in session #1
demo@ORA26AI>
demo@ORA26AI> commit;
Commit complete.
demo@ORA26AI>
and come back to session #2 - we see this
demo@ORA26AI> select 'OLTP', oltp.* from oltp minus select 'OLTP', copy.* from copy
2 union all
3 select 'COPY', copy.* from copy minus select 'COPY', oltp.* from oltp;
'OLT USERNAME USER_ID CREATED COM O INH DEFAULT_COLLATI IMP ALL EXT DIC CLO APP LAST_UPDATED
---- -------- ---------- ------------------ --- - --- --------------- --- --- --- --- --- --- ------------------
OLTP ABC 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:01:09
COPY SYS 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:00:48
demo@ORA26AI> select to_date('&FIRST_REFRESH') first_refresh,
2 to_date('&NEXT_REFRESH') next_refresh
3 from dual;
old 1: select to_date('&FIRST_REFRESH') first_refresh,
new 1: select to_date('12-mar-26 12:01:35') first_refresh,
old 2: to_date('&NEXT_REFRESH') next_refresh
new 2: to_date('12-mar-26 12:01:49') next_refresh
FIRST_REFRESH NEXT_REFRESH
------------------ ------------------
12-mar-26 12:01:35 12-mar-26 12:01:49
demo@ORA26AI> merge into copy
2 using
3 (select * from oltp
4 where last_updated >= to_date('&NEXT_REFRESH') ) OLTP
5 on ( copy.user_id = oltp.user_id )
6 when matched then
7 update set username = oltp.username, created = oltp.created,
8 last_updated = oltp.last_updated
9 when not matched then
10 insert (username,user_id,created,last_updated) values
11 (oltp.username, oltp.user_id, oltp.created, oltp.last_updated );
old 4: where last_updated >= to_date('&NEXT_REFRESH') ) OLTP
new 4: where last_updated >= to_date('12-mar-26 12:01:49') ) OLTP
0 rows merged.
demo@ORA26AI> select 'OLTP', oltp.* from oltp minus select 'OLTP', copy.* from copy
2 union all
3 select 'COPY', copy.* from copy minus select 'COPY', oltp.* from oltp;
'OLT USERNAME USER_ID CREATED COM O INH DEFAULT_COLLATI IMP ALL EXT DIC CLO APP LAST_UPDATED
---- -------- ---------- ------------------ --- - --- --------------- --- --- --- --- --- --- ------------------
OLTP ABC 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:01:09
COPY SYS 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:00:48
demo@ORA26AI> select to_date('&FIRST_REFRESH') first_refresh,
2 to_date('&NEXT_REFRESH') next_refresh
3 from dual;
old 1: select to_date('&FIRST_REFRESH') first_refresh,
new 1: select to_date('12-mar-26 12:01:35') first_refresh,
old 2: to_date('&NEXT_REFRESH') next_refresh
new 2: to_date('12-mar-26 12:01:49') next_refresh
FIRST_REFRESH NEXT_REFRESH
------------------ ------------------
12-mar-26 12:01:35 12-mar-26 12:01:49
to avoid these kind of things to happen, we need to look for open transaction during the first refresh, if exists, then we need to pick that time instead of sysdate.
having this below sql for the "NEXT_refresh" in the above sequence would have solved the problem.
column NEXT_REFRESH new_val NEXT_REFRESH
select nvl( min(to_date(start_time,'mm/dd/rr hh24:mi:ss')),sysdate) as NEXT_refresh
from v$transaction;
running the above demo from session #2
demo@ORA26AI> column FIRST_REFRESH new_val FIRST_REFRESH
demo@ORA26AI> select sysdate FIRST_refresh from dual;
FIRST_REFRESH
------------------
12-mar-26 12:09:30
demo@ORA26AI> create table copy as select * from oltp;
Table created.
demo@ORA26AI> column NEXT_REFRESH new_val NEXT_REFRESH
demo@ORA26AI> select nvl( min(to_date(start_time,'mm/dd/rr hh24:mi:ss')),sysdate) as NEXT_refresh
2 from v$transaction;
NEXT_REFRESH
------------------
12-mar-26 12:09:25
demo@ORA26AI> merge into copy
2 using
3 (select * from oltp
4 where last_updated >= to_date('&FIRST_REFRESH') ) OLTP
5 on ( copy.user_id = oltp.user_id )
6 when matched then
7 update set username = oltp.username, created = oltp.created,
8 last_updated = oltp.last_updated
9 when not matched then
10 insert (username,user_id,created,last_updated) values
11 (oltp.username, oltp.user_id, oltp.created, oltp.last_updated );
old 4: where last_updated >= to_date('&FIRST_REFRESH') ) OLTP
new 4: where last_updated >= to_date('12-mar-26 12:09:30') ) OLTP
0 rows merged.
demo@ORA26AI> /* these tables are the same now, right -- nothing could be 'wrong'
demo@ORA26AI> but wait.... goto that other session and type 'commit' */
demo@ORA26AI>
demo@ORA26AI>
demo@ORA26AI>
demo@ORA26AI>
demo@ORA26AI> select 'OLTP', oltp.* from oltp minus select 'OLTP', copy.* from copy
2 union all
3 select 'COPY', copy.* from copy minus select 'COPY', oltp.* from oltp;
'OLT USERNAME USER_ID CREATED COM O INH DEFAULT_COLLATI IMP ALL EXT DIC CLO APP LAST_UPDATED
---- -------- ---------- ------------------ --- - --- --------------- --- --- --- --- --- --- ------------------
OLTP ABC 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:09:26
COPY SYS 0 08-oct-25 22:00:58 YES Y YES USING_NLS_COMP NO NO NO NO YES NO 12-mar-26 12:08:46
demo@ORA26AI> select to_date('&FIRST_REFRESH') first_refresh,
2 to_date('&NEXT_REFRESH') next_refresh
3 from dual;
old 1: select to_date('&FIRST_REFRESH') first_refresh,
new 1: select to_date('12-mar-26 12:09:30') first_refresh,
old 2: to_date('&NEXT_REFRESH') next_refresh
new 2: to_date('12-mar-26 12:09:25') next_refresh
FIRST_REFRESH NEXT_REFRESH
------------------ ------------------
12-mar-26 12:09:30 12-mar-26 12:09:25
demo@ORA26AI> merge into copy
2 using
3 (select * from oltp
4 where last_updated >= to_date('&NEXT_REFRESH') ) OLTP
5 on ( copy.user_id = oltp.user_id )
6 when matched then
7 update set username = oltp.username, created = oltp.created,
8 last_updated = oltp.last_updated
9 when not matched then
10 insert (username,user_id,created,last_updated) values
11 (oltp.username, oltp.user_id, oltp.created, oltp.last_updated );
old 4: where last_updated >= to_date('&NEXT_REFRESH') ) OLTP
new 4: where last_updated >= to_date('12-mar-26 12:09:25') ) OLTP
1 row merged.
demo@ORA26AI> select 'OLTP', oltp.* from oltp minus select 'OLTP', copy.* from copy
2 union all
3 select 'COPY', copy.* from copy minus select 'COPY', oltp.* from oltp;
no rows selected
demo@ORA26AI>