197

Is there an SQL instruction to retrieve the value of a sequence that does not increment it.

Thanks.

EDIT AND CONCLUSION

As stated by Justin Cave It's not useful to try to "save" sequence number so

select a_seq.nextval from dual;

is good enough to check a sequence value.

I still keep Ollie answer as the good one because it answered the initial question. but ask yourself about the necessity of not modifying the sequence if you ever want to do it.

wolφi
  • 8,091
  • 2
  • 35
  • 64
frno
  • 2,641
  • 2
  • 18
  • 19
  • 7
    Why? What is the problem you are trying to solve? If you're using sequences correctly, you should never care what sequence values have been assigned to other sessions or what values might be assigned to subsequent sessions. – Justin Cave Apr 18 '12 at 13:56
  • 4
    It's a check after data migration to be sure the sequence have been updated correctly according to the data migrated – frno Apr 18 '12 at 14:04
  • 5
    Then what is the downside to simply getting the `nextval` of the sequence to test then? You're not assuming that sequences will be gap-free, right? So "wasting" a sequence value shouldn't be an issue. – Justin Cave Apr 18 '12 at 14:45
  • I guess you're right, I didn't want to change the state of the db for that check but to be honest I don't know why. thanks for your insight. nevertheless I did learn your stuff about sequence, thank you all ! – frno Apr 18 '12 at 14:55
  • Assuming you can reliably get the value of a sequence, what is your oracle against which you are checking that the sequence has been updated properly? – Shannon Severance Apr 18 '12 at 16:58
  • just as a side note, if you are looking to make sure that you do NOT actually cause a +1 on the sequence, you are safer doing the select on last_number from user_sequences assuming you also know that it is a user sequence. – gcoleman0828 Jul 14 '15 at 15:14
  • 1
    @JustinCave, have a system I'm doing a data migration on, and I have no idea if gap-free is required or not. Having as few side effects as possible prevents me and future people from possibly chasing a red-herring troubleshooting other problems. – Nathan Goings Jun 14 '20 at 06:30

8 Answers8

205
SELECT last_number
  FROM all_sequences
 WHERE sequence_owner = '<sequence owner>'
   AND sequence_name = '<sequence_name>';

You can get a variety of sequence metadata from user_sequences, all_sequences and dba_sequences.

These views work across sessions.

EDIT:

If the sequence is in your default schema then:

SELECT last_number
  FROM user_sequences
 WHERE sequence_name = '<sequence_name>';

If you want all the metadata then:

SELECT *
  FROM user_sequences
 WHERE sequence_name = '<sequence_name>';

EDIT2:

A long winded way of doing it more reliably if your cache size is not 1 would be:

SELECT increment_by I
  FROM user_sequences
 WHERE sequence_name = 'SEQ';

      I
-------
      1

SELECT seq.nextval S
  FROM dual;

      S
-------
   1234

-- Set the sequence to decrement by 
-- the same as its original increment
ALTER SEQUENCE seq 
INCREMENT BY -1;

Sequence altered.

SELECT seq.nextval S
  FROM dual;

      S
-------
   1233

-- Reset the sequence to its original increment
ALTER SEQUENCE seq 
INCREMENT BY 1;

Sequence altered.

Just beware that if others are using the sequence during this time - they (or you) may get

ORA-08004: sequence SEQ.NEXTVAL goes below the sequences MINVALUE and cannot be instantiated

Also, you might want to set the cache to NOCACHE prior to the resetting and then back to its original value afterwards to make sure you've not cached a lot of values.

starball
  • 20,030
  • 7
  • 43
  • 238
Ollie
  • 17,058
  • 7
  • 48
  • 59
  • Just tried it but i don't have access to an 'all_sequences' table. Is it a special object you only see with admin credentials ? – frno Apr 18 '12 at 13:28
  • Use user_sequences. That will work if you own the sequence you're looking at. – Jim Hudson Apr 18 '12 at 13:32
  • 1
    `ALL_SEQUENCES` is a view. If you don't have access to it then try selecting from `USER_SEQUENCES` if the sequence is in your default schema. (You won't need the `sequence_owner = ''` clause for `USER_SEQUENCES`). – Ollie Apr 18 '12 at 13:33
  • 18
    The `LAST_NUMBER` in `ALL_SEQUENCES` will not be the last number that a session was actually given and will not be the number that would be returned from a call to `sequence_name.nextval` in general. Assuming you have set the sequence to `CACHE` more than 1 (the default is 20), `LAST_NUMBER` will be the last number that is in the cache. There is no guarantee that this number will ever actually be given to any session. – Justin Cave Apr 18 '12 at 13:40
  • @JustinCave, true, but then querying `CURRVAL` could generate `ORA-08002` if `NEXTVAL` hadn't been called and then calling `NEXTVAL` changes the sequence. I guess that the answer is somewhere in between the two. If the sequence is queried a lot in the session then `CURRVAL` will probably be fine but if the cache is set to none then `LAST_NUMBER` is reliable. Neither is necessarily perfect though. :-( – Ollie Apr 18 '12 at 13:48
  • 3
    `ALTER SEQUENCE seq INCREMENT BY -1;` is going to be a problem unless one can **guarantee** that that no other session will call `seq.nextval`. Otherwise the sequence will be handing out duplicate values, which is usually not what one want. – Shannon Severance Apr 18 '12 at 17:00
  • 2
    The OP did say "It's a check after data migration" so it's not a stretch to assume the DB isn't in general use but it could be an issue if this wasn't the case. – Ollie Apr 18 '12 at 17:02
  • `ALTER SEQUENCE` is DDL. That means an implicit commit. So the last example is a trap. Also first and second examples will give you wrong values if caching is enabled. Don't do this. Don't even advocate this. Sequences are designed to perform an atomic operation that gives you an incrementing unique numerical identifier. That's all the guarantee it gives you. If you really need to have a sequence that is not atomic like the built in ones, use something like `MAX`. – sampathsris Aug 01 '14 at 02:58
149

select MY_SEQ_NAME.currval from DUAL;

Keep in mind that it only works if you ran select MY_SEQ_NAME.nextval from DUAL; in the current sessions.

RonK
  • 9,472
  • 8
  • 51
  • 87
8

The follows is often used:

select field_SQ.nextval from dual;  -- it will increase the value by 1 for each run
select field_SQ.currval from DUAL;

However the following is able to change the sequence to what you expected. The 1 can be an integer (negative or positive)

alter sequence field_SQ increment by 1 minvalue 0
caot
  • 3,066
  • 35
  • 37
2

This is not an answer, really and I would have entered it as a comment had the question not been locked. This answers the question:

Why would you want it?

Assume you have a table with the sequence as the primary key and the sequence is generated by an insert trigger. If you wanted to have the sequence available for subsequent updates to the record, you need to have a way to extract that value.

In order to make sure you get the right one, you might want to wrap the INSERT and RonK's query in a transaction.

RonK's Query:

select MY_SEQ_NAME.currval from DUAL;

In the above scenario, RonK's caveat does not apply since the insert and update would happen in the same session.

Ainsworth
  • 69
  • 3
  • 8
1

I also tried to use CURRVAL, in my case to find out if some process inserted new rows to some table with that sequence as Primary Key. My assumption was that CURRVAL would be the fastest method. But a) CurrVal does not work, it will just get the old value because you are in another Oracle session, until you do a NEXTVAL in your own session. And b) a select max(PK) from TheTable is also very fast, probably because a PK is always indexed. Or select count(*) from TheTable. I am still experimenting, but both SELECTs seem fast.

I don't mind a gap in a sequence, but in my case I was thinking of polling a lot, and I would hate the idea of very large gaps. Especially if a simple SELECT would be just as fast.

Conclusion:

  • CURRVAL is pretty useless, as it does not detect NEXTVAL from another session, it only returns what you already knew from your previous NEXTVAL
  • SELECT MAX(...) FROM ... is a good solution, simple and fast, assuming your sequence is linked to that table
Roland
  • 4,619
  • 7
  • 49
  • 81
1

If your use case is that some backend code inserts a record, then the same code wants to retrieve the last insert id, without counting on any underlying data access library preset function to do this, then, as mentioned by others, you should just craft your SQL query using SEQ_MY_NAME.NEXTVAL for the column you want (usually the primary key), then just run statement SELECT SEQ_MY_NAME.CURRVAL FROM dual from the backend.

Remember, CURRVAL is only callable if NEXTVAL has been priorly invoked, which is all naturally done in the strategy above...

Fabien Haddadi
  • 1,814
  • 17
  • 22
0

We can use the below query to get the sequence next value.

select last_number from dba_sequences where sequence_name = '<sequence name>';
Chamith
  • 69
  • 10
-2

My original reply was factually incorrect and I'm glad it was removed. The code below will work under the following conditions a) you know that nobody else modified the sequence b) the sequence was modified by your session. In my case, I encountered a similar issue where I was calling a procedure which modified a value and I'm confident the assumption is true.

SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;

Sadly, if you didn't modify the sequence in your session, I believe others are correct in stating that the NEXTVAL is the only way to go.

georgejo
  • 25
  • 3