Come recuperare il valore corrente di una sequenza di Oracle senza incrementarlo?


156

Esiste un'istruzione SQL per recuperare il valore di una sequenza che non lo incrementa.

Grazie.

MODIFICA E CONCLUSIONE

Come affermato da Justin Cave Non è utile provare a "salvare" il numero di sequenza così

select a_seq.nextval from dual;

è abbastanza buono per controllare un valore di sequenza.

Continuo a tenere la risposta di Ollie come buona perché ha risposto alla domanda iniziale. ma chiediti della necessità di non modificare la sequenza se mai lo desideri.


5
Perché? Qual è il problema che stai cercando di risolvere? Se stai usando correttamente le sequenze, non dovresti mai preoccuparti di quali valori di sequenza sono stati assegnati ad altre sessioni o quali valori potrebbero essere assegnati a sessioni successive.
Grotta di Giustino,

3
È un controllo dopo la migrazione dei dati assicurarsi che la sequenza sia stata aggiornata correttamente in base ai dati migrati
fr

3
Allora qual è il rovescio della medaglia semplicemente ottenere il nextvaltest della sequenza da testare allora? Non stai supponendo che le sequenze saranno prive di gap, giusto? Quindi "sprecare" un valore di sequenza non dovrebbe essere un problema.
Grotta di Giustino

Immagino tu abbia ragione, non volevo cambiare lo stato del db per quel controllo ma ad essere sincero non so perché. grazie per la tua comprensione. tuttavia ho imparato le tue cose sulla sequenza, grazie a tutti!
fr

Supponendo che tu possa ottenere in modo affidabile il valore di una sequenza, qual è il tuo oracolo rispetto al quale stai verificando che la sequenza sia stata aggiornata correttamente?
Shannon Severance,

Risposte:


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

È possibile ottenere una varietà di sequenza di metadati da user_sequences, all_sequencesedba_sequences .

Queste viste funzionano attraverso le sessioni.

MODIFICARE:

Se la sequenza è nello schema predefinito, allora:

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

Se vuoi tutti i metadati, allora:

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

Spero che sia d'aiuto...

EDIT2:

Un modo lungo e complicato di farlo in modo più affidabile se la dimensione della cache non è 1 sarebbe:

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.

Fai attenzione che se altri usano la sequenza durante questo periodo, loro (o te) potrebbero ottenerli

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

Inoltre, potresti voler impostare la cache su NOCACHEprima del ripristino e quindi tornare al suo valore originale in seguito per assicurarti di non aver memorizzato nella cache molti valori.


Ho appena provato ma non ho accesso a una tabella "all_sequences". È un oggetto speciale che vedi solo con le credenziali di amministratore?
fr

1
ALL_SEQUENCESè una vista. Se non hai accesso ad esso, prova a selezionare da USER_SEQUENCESse la sequenza è nello schema predefinito. (Non è necessaria la sequence_owner = '<sequence_owner>'clausola per USER_SEQUENCES).
Ollie

15
L' LAST_NUMBERin ALL_SEQUENCESnon sarà l'ultimo numero che una sessione è stato effettivamente dato e non sarà il numero che verrebbe restituito da una chiamata a sequence_name.nextvalin generale. Supponendo di aver impostato la sequenza su CACHEpiù di 1 (il valore predefinito è 20), LAST_NUMBERsarà l'ultimo numero presente nella cache. Non vi è alcuna garanzia che questo numero verrà mai effettivamente assegnato a qualsiasi sessione.
Grotta di Giustino

2
ALTER SEQUENCE seq INCREMENT BY -1;sarà un problema a meno che uno non possa garantire che nessun'altra sessione chiamerà seq.nextval. Altrimenti la sequenza distribuirà valori duplicati, che di solito non è quello che si desidera.
Shannon Severance,

1
L'OP ha detto "È un controllo dopo la migrazione dei dati", quindi non è un tratto ipotizzare che il DB non sia di uso generale, ma potrebbe essere un problema se non fosse così.
Ollie

122

select MY_SEQ_NAME.currval from DUAL;

Tieni presente che funziona solo se hai eseguito select MY_SEQ_NAME.nextval from DUAL;le sessioni correnti.


1
Grazie mille per la tua risposta. Devo usarlo all'interno di Boomi e cercavo una soluzione su e giù
imparando ... il

0

La mia risposta originale era effettivamente errata e sono contento che sia stata rimossa. Il codice seguente funzionerà nelle seguenti condizioni a) sai che nessun altro ha modificato la sequenza b) la sequenza è stata modificata dalla tua sessione. Nel mio caso, ho riscontrato un problema simile in cui stavo chiamando una procedura che ha modificato un valore e sono sicuro che l'ipotesi sia vera.

SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;

Purtroppo, se non hai modificato la sequenza nella tua sessione, credo che gli altri abbiano ragione nel dichiarare che NEXTVAL è l'unica strada da percorrere.


0

Questa non è una risposta, davvero e l'avrei inserita come commento se la domanda non fosse stata bloccata. Questo risponde alla domanda:

Perché lo vorresti?

Supponiamo di avere una tabella con la sequenza come chiave primaria e la sequenza viene generata da un trigger di inserimento. Se si desidera avere la sequenza disponibile per gli aggiornamenti successivi al record, è necessario disporre di un modo per estrarre quel valore.

Per assicurarti di ottenere quello giusto, potresti voler racchiudere la query INSERT e RonK in una transazione.

Query di RonK:

select MY_SEQ_NAME.currval from DUAL;

Nello scenario sopra, l'avvertimento di RonK non si applica poiché l'inserimento e l'aggiornamento avverrebbero nella stessa sessione.


0

Ho anche provato a usare CURRVAL, nel mio caso per scoprire se qualche processo ha inserito nuove righe in una tabella con quella sequenza come chiave primaria. La mia ipotesi era che CURRVAL sarebbe stato il metodo più veloce. Ma a) CurrVal non funziona, otterrà solo il vecchio valore perché ci si trova in un'altra sessione Oracle, fino a quando non si esegue un NEXTVAL nella propria sessione. E b) a select max(PK) from TheTableè anche molto veloce, probabilmente perché un PK è sempre indicizzato. Oselect count(*) from TheTable . Sto ancora sperimentando, ma entrambi i SELECT sembrano veloci.

Non mi dispiace un divario in una sequenza, ma nel mio caso stavo pensando di sondare molto e oderei l'idea di divari molto grandi. Soprattutto se un semplice SELECT sarebbe altrettanto veloce.

Conclusione:

  • CURRVAL è piuttosto inutile, poiché non rileva NEXTVAL da un'altra sessione, restituisce solo ciò che già sapevi dal tuo precedente NEXTVAL
  • SELEZIONA MAX (...) DA ... è una buona soluzione, semplice e veloce, supponendo che la sequenza sia collegata a quella tabella
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.