Como recuperar o valor atual de uma sequência oracle sem incrementá-lo?

156

Existe uma instrução SQL para recuperar o valor de uma sequência que não a incrementa.

Obrigado.

EDIÇÃO E CONCLUSÃO

Conforme declarado por Justin Cave Não é útil tentar "salvar" o número da sequência para

select a_seq.nextval from dual;

é bom o suficiente para verificar um valor de sequência.

Ainda mantenho a resposta de Ollie como boa porque ela respondeu à pergunta inicial. mas pergunte a si mesmo sobre a necessidade de não modificar a sequência, se você quiser fazê-lo.

frno
fonte
5
Por quê? Qual é o problema que você está tentando resolver? Se você estiver usando sequências corretamente, nunca se preocupe com os valores de sequência atribuídos a outras sessões ou com os valores que podem ser atribuídos às sessões subseqüentes.
Justin Caverna
3
É uma verificação após a migração de dados para ter certeza da sequência foram atualizados corretamente de acordo com os dados migrados
frno
3
Então, qual é a desvantagem de simplesmente nextvaltestar a sequência? Você não está assumindo que as sequências serão livres de falhas, certo? Portanto, "desperdiçar" um valor de sequência não deve ser um problema.
11557 Justin Bieber
Acho que você está certo, não queria mudar o estado do banco de dados para essa verificação, mas, para ser sincero, não sei por que. obrigado pela sua compreensão. no entanto, eu aprendi suas coisas sobre sequência, obrigado a todos!
frno
Supondo que você possa obter com segurança o valor de uma sequência, qual é o seu oráculo contra o qual você está verificando se a sequência foi atualizada corretamente?
21603 Shannon Severance

Respostas:

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

Você pode obter vários metadados de sequência de user_sequences, all_sequencese dba_sequences.

Essas visualizações funcionam em todas as sessões.

EDITAR:

Se a sequência estiver no seu esquema padrão, então:

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

Se você deseja todos os metadados, então:

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

Espero que ajude...

EDIT2:

Uma maneira prolongada de fazê-lo de maneira mais confiável se o tamanho do cache não for 1 seria:

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.

Apenas tome cuidado para que, se outras pessoas estiverem usando a sequência durante esse período - elas (ou você)

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

Além disso, convém definir o cache como NOCACHEanterior à redefinição e depois retornar ao seu valor original posteriormente para garantir que você não tenha armazenado muitos valores em cache.

Ollie
fonte
Apenas tentei, mas não tenho acesso a uma tabela 'all_sequences'. É um objeto especial que você vê apenas com credenciais de administrador?
frno
1
ALL_SEQUENCESé uma visão. Se você não tiver acesso a ele, tente selecionar USER_SEQUENCESse a sequência está no seu esquema padrão. (Você não precisará da sequence_owner = '<sequence_owner>'cláusula para USER_SEQUENCES).
Ollie
15
O LAST_NUMBERin ALL_SEQUENCESnão será o último número que uma sessão foi realmente fornecida e não será o número que seria retornado de uma chamada para sequence_name.nextvalem geral. Supondo que você configurou a sequência para CACHEmais de 1 (o padrão é 20), LAST_NUMBERserá o último número que está no cache. Não há garantia de que esse número seja realmente fornecido a qualquer sessão.
Justin Caverna
2
ALTER SEQUENCE seq INCREMENT BY -1;será um problema, a menos que se possa garantir que nenhuma outra sessão será chamada seq.nextval. Caso contrário, a sequência estará distribuindo valores duplicados, o que geralmente não é o que se deseja.
Shannon Severance
1
O OP disse "É uma verificação após a migração de dados", portanto, não é exagero supor que o banco de dados não esteja em uso geral, mas pode ser um problema se esse não for o caso.
Ollie
122

select MY_SEQ_NAME.currval from DUAL;

Lembre-se de que só funciona se você executou select MY_SEQ_NAME.nextval from DUAL;nas sessões atuais.

RonK
fonte
1
Muito obrigado pela sua resposta. Eu tenho que usar isso dentro Boomi e estava à procura de uma solução para cima e para baixo
aprendizagem ...
0

Minha resposta original estava incorreta e estou feliz por ter sido removida. O código abaixo funcionará nas seguintes condições: a) você sabe que ninguém mais modificou a sequência; b) a sequência foi modificada pela sua sessão. No meu caso, encontrei um problema semelhante no qual estava chamando um procedimento que modifica um valor e estou confiante de que a suposição é verdadeira.

SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;

Infelizmente, se você não modificou a sequência em sua sessão, acredito que outras pessoas estejam corretas ao afirmar que o NEXTVAL é o único caminho a percorrer.

georgejo
fonte
0

Esta não é uma resposta, na verdade e eu a teria inserido como um comentário se a pergunta não tivesse sido bloqueada. Isso responde à pergunta:

Porque você deveria querer isso?

Suponha que você tenha uma tabela com a sequência como chave primária e a sequência seja gerada por um gatilho de inserção. Se você quiser ter a sequência disponível para atualizações subseqüentes no registro, precisará de uma maneira de extrair esse valor.

Para garantir que você obtenha a correta, você pode agrupar a consulta INSERT e RonK em uma transação.

Consulta de RonK:

select MY_SEQ_NAME.currval from DUAL;

No cenário acima, a ressalva de RonK não se aplica, pois a inserção e a atualização aconteceriam na mesma sessão.

Ainsworth
fonte
0

Também tentei usar CURRVAL, no meu caso, para descobrir se algum processo inseriu novas linhas em alguma tabela com essa sequência como Chave Primária. Minha suposição era que CURRVAL seria o método mais rápido. Mas a) CurrVal não funciona, ele apenas obterá o valor antigo porque você está em outra sessão do Oracle, até fazer um NEXTVAL em sua própria sessão. E b) a select max(PK) from TheTabletambém é muito rápido, provavelmente porque uma PK é sempre indexada. Ouselect count(*) from TheTable . Ainda estou experimentando, mas os dois SELECTs parecem rápidos.

Não me importo com uma lacuna na sequência, mas no meu caso eu estava pensando muito em pesquisar, e odiaria a ideia de lacunas muito grandes. Especialmente se um simples SELECT fosse tão rápido.

Conclusão:

  • CURRVAL é bastante inútil, pois não detecta o NEXTVAL de outra sessão, apenas retorna o que você já sabia do seu NEXTVAL anterior
  • SELECT MAX (...) FROM ... é uma boa solução, simples e rápida, supondo que sua sequência esteja vinculada a essa tabela
Roland
fonte