How to Fetch All Current Identity Values in Oracle

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

4 thoughts on “How to Fetch All Current Identity Values in Oracle

  1. result for me is no so nice:


    SQL> create table t1 (col1 number generated always as identity);

    Table created.

    SQL> create table t2 (col2 number generated always as identity);

    Table created.

    SQL> with
    2 function current_value(p_table_name varchar2) return number is
    3 v_current number;
    4 begin
    5 for rec in (
    6 select data_default
    7 from user_tab_cols
    8 where table_name = p_table_name
    9 and data_default is not null
    10 and identity_column = 'YES'
    11 )
    12 loop
    13 execute immediate replace(
    14 'select ' || rec.data_default || ' from dual',
    15 '.nextval',
    16 '.currval'
    17 ) into v_current;
    18 return v_current;
    19 end loop;
    20
    21 return null;
    22 end;
    23 select *
    24 from (
    25 select table_name, current_value(table_name) current_value
    26 from user_tables
    27 where table_name in ('T1', 'T2')
    28 )
    29 where current_value is not null
    30 order by table_name;
    31 /
    order by table_name
    *
    ERROR at line 30:
    ORA-08002: sequence ISEQ$$_1954315.CURRVAL is not yet defined in this session
    ORA-06512: at line 22

  2. Not related, but did you ever considered making a JOOQ for javascript?
    Having the same quality as JOOQ has, it can easily dominate the SQL market in javascript.
    I can be wrong, but JOOQ looks to me far more complete than solutions like sequelize.
    But I guess the lack of a JDBC like API in javascript would make this quite a challenge…

    1. Thank you very much for your comment. Yes, of course, we’re constantly thinking about how to bring jOOQ to other languages, but that’s a lot of effort and needs a lot of preparation. Right now, we’re looking into how we can improve the Java version in a way that we can reuse our API as much as possible in other languages (e.g. by generating the API and a big chunk of the implementation from a meta language).

      JavaScript (or rather: TypeScript) will be a very interesting candidate. But I think it’ll still take until 2020/2021 until we can ship something.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.