The psuedo-column ORA_ROWSCN is assigned at commit time and can be used to identify the order of commits, with the following caveats:
- The table must be created with the ROWDEPENDENCIES clause. If this isn't done then commits will be at the block level, not the row level. You cannot alter a table to have this, you must drop and re-create it
- Updated data will also have the ORA_ROWSCN updated on commit
- It is approximate, from the Oracle documentation:
For each row, ORA_ROWSCN returns the conservative upper bound system
change number (SCN) of the most recent change to the row in the
current session. This pseudocolumn is useful for
determining approximately when a row was last updated. It is not
absolutely precise, because Oracle tracks SCNs by transaction
committed for the block in which the row resides. You can obtain a
more fine-grained approximation of the SCN by creating your tables
with row-level dependency tracking
To see it in effect:
16:43:49 SQL>-- session 1
16:43:53 SQL>create table t ( x integer, y timestamp default systimestamp) ROWDEPENDENCIES ;
Table created.
16:43:54 SQL>
16:43:54 SQL>insert into t (x) values (1);
1 row created.
16:43:54 SQL>
16:43:57 SQL>-- session 2
16:43:57 SQL>insert into t (x) values (2);
1 row created.
16:43:57 SQL>commit;
Commit complete.
16:43:57 SQL>
16:43:54 SQL>-- session 1
16:44:02 SQL>commit;
Commit complete.
16:44:02 SQL>select ORA_ROWSCN, t.*
16:44:02 2 from t
16:44:02 3 order by ora_rowscn;
ORA_ROWSCN X Y
-------------------- ---------- ----------------------------
2,495,575,731,731 2 18-JUN-12 16.40.16.144909
2,495,575,731,777 1 18-JUN-12 16.40.12.447235
16:44:02 SQL>select ORA_ROWSCN, t.*
16:44:02 2 from t
16:44:02 3 order by y;
ORA_ROWSCN X Y
-------------------- ---------- ----------------------------
2,495,575,731,777 1 18-JUN-12 16.40.12.447235
2,495,575,731,731 2 18-JUN-12 16.40.16.144909
16:44:03 SQL>
If you do this without ROWDEPENDENCIES they will come out with the same ORA_ROWSCN because the rows are on the same block:
16:44:03 SQL>drop table t purge;
Table dropped.
16:46:36 SQL>
16:46:36 SQL>create table t ( x integer, y timestamp default systimestamp);
Table created.
16:46:36 SQL>
16:46:36 SQL>insert into t (x) values (1);
1 row created.
16:46:36 SQL>commit;
Commit complete.
16:46:36 SQL>
16:46:36 SQL>insert into t (x) values (2);
1 row created.
16:46:36 SQL>
16:46:36 SQL>commit;
Commit complete.
16:46:36 SQL>select ORA_ROWSCN, t.*
16:46:36 2 from t
16:46:36 3 order by ora_rowscn;
ORA_ROWSCN X Y
-------------------- ---------- --------------------------------------------
2,495,575,732,066 2 18-JUN-12 16.42.54.443898
2,495,575,732,066 1 18-JUN-12 16.42.54.426690
Note the ORA_ROWSCNs are the same in the second example.
You can't index the ORA_ROWSCN, so filtering on this will result in full table scans. If combined with filtering on an insert timestamp you could overcome this however (which should also help prevent updated rows appearing, if that's the behaviour you want)