Oracle 12c has introduced the useful SQL standard IDENTITY
feature, which is essentially just syntax sugar for binding a sequence to a column default. We can use it like this:
create table t1 (col1 number generated always as identity); create table t2 (col2 number generated always as identity); insert into t1 values (default); insert into t1 values (default); insert into t1 values (default); insert into t2 values (default); select * from t1; select * from t2;
Which produces
COL1 ---- 1 2 3 COL2 ---- 1
For unit testing against our database, we might want to know what “state” our identities are in. For each table, we would like to know the next value such an identity would produce. If we knew all the backing sequence names, we could query their seq.currval
, but we don’t know those sequence names as they are generated.
However, we can query the dictionary views to get this information as follows:
select data_default from user_tab_cols where data_default is not null and identity_column = 'YES' and table_name in ('T1', 'T2');
An alternative is to query user_tab_identity_cols
This would produce:
"TEST"."ISEQ$$_116601".nextval "TEST"."ISEQ$$_116603".nextval
Now, if we’re lazy, we could just run EXECUTE IMMEDIATE
on each of those expressions and we’re done:
set serveroutput on declare v_current number; begin for rec in ( select table_name, data_default from user_tab_cols where data_default is not null and identity_column = 'YES' and table_name in ('T1', 'T2') ) loop execute immediate replace( 'select ' || rec.data_default || ' from dual', '.nextval', '.currval' ) into v_current; dbms_output.put_line( 'Table : ' || rec.table_name || ', currval : ' || v_current ); end loop; end; /
This would produce:
Table : T1, currval : 3 Table : T2, currval : 1
Alternatively, if you want this result to be a SQL result instead of DBMS_OUTPUT
content, you could run this:
with function current_value(p_table_name varchar2) return number is v_current number; begin for rec in ( select data_default from user_tab_cols where table_name = p_table_name and data_default is not null and identity_column = 'YES' ) loop execute immediate replace( 'select ' || rec.data_default || ' from dual', '.nextval', '.currval' ) into v_current; return v_current; end loop; return null; end; select * from ( select table_name, current_value(table_name) current_value from user_tables where table_name in ('T1', 'T2') ) where current_value is not null order by table_name; /
The alternative using user_tab_identity_cols
would look like this:
with function current_value(p_table_name varchar2) return number is v_current number; begin for rec in ( select sequence_name from user_tab_identity_cols where table_name = p_table_name ) loop execute immediate 'select ' || rec.sequence_name || '.currval from dual' into v_current; return v_current; end loop; return null; end; select * from ( select table_name, current_value(table_name) current_value from user_tables ) where current_value is not null order by table_name; /
The result is now a nice SQL result set:
TABLE_NAME CURRENT_VALUE -------------------------- T1 3 T2 1