Jak pobrać bieżącą wartość sekwencji wyroczni bez jej zwiększania?

156

Czy istnieje instrukcja SQL pobierająca wartość sekwencji, która jej nie zwiększa.

Dzięki.

EDYCJA I WNIOSEK

Jak stwierdził Justin Cave Nie ma sensu próbować "zapisywać" numeru sekwencji

select a_seq.nextval from dual;

jest wystarczająco dobry, aby sprawdzić wartość sekwencji.

Nadal uważam, że odpowiedź Ollie jest dobra, ponieważ odpowiedziała na pierwsze pytanie. ale zadaj sobie pytanie o konieczność nie modyfikowania sekwencji, jeśli kiedykolwiek zechcesz to zrobić.

frno
źródło
5
Czemu? Jaki problem próbujesz rozwiązać? Jeśli poprawnie używasz sekwencji, nigdy nie powinieneś się przejmować, jakie wartości sekwencji zostały przypisane do innych sesji lub jakie wartości mogą zostać przypisane do kolejnych sesji.
Justin Cave
3
Jest to sprawdzenie po migracji danych, aby upewnić się, że sekwencja została poprawnie zaktualizowana zgodnie z migrowanymi danymi
dnia
3
Więc jaki jest minus po prostu nextvalprzetestowania sekwencji? Nie zakładasz, że sekwencje będą wolne od luk, prawda? Dlatego „marnowanie” wartości sekwencji nie powinno stanowić problemu.
Justin Cave
Chyba masz rację, nie chciałem zmieniać stanu bazy danych do tego czeku, ale szczerze mówiąc, nie wiem dlaczego. dzięki za wgląd. niemniej jednak nauczyłem się waszych rzeczy o sekwencji, dziękuję wszystkim!
pt
Zakładając, że możesz wiarygodnie uzyskać wartość sekwencji, jaka jest twoja wyrocznia, względem której sprawdzasz, czy sekwencja została poprawnie zaktualizowana?
Shannon Severance

Odpowiedzi:

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

Można uzyskać wiele metadanych z sekwencji user_sequences, all_sequencesadba_sequences .

Te widoki działają w różnych sesjach.

EDYTOWAĆ:

Jeśli sekwencja znajduje się w Twoim domyślnym schemacie, to:

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

Jeśli chcesz wszystkie metadane, to:

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

Mam nadzieję, że to pomoże...

EDYCJA2:

Długotrwały sposób na zrobienie tego bardziej niezawodnie, jeśli rozmiar pamięci podręcznej jest inny niż 1, to:

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.

Uważaj tylko, jeśli inni używają sekwencji w tym czasie - oni (lub ty) mogą dostać

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

Możesz również ustawić pamięć podręczną na NOCACHEprzed resetowaniem, a następnie przywrócić jej pierwotną wartość, aby upewnić się, że nie zapisałeś wielu wartości w pamięci podręcznej.

Ollie
źródło
Właśnie próbowałem, ale nie mam dostępu do tabeli „all_sequences”. Czy jest to specjalny obiekt, który widzisz tylko z poświadczeniami administratora?
pt
1
ALL_SEQUENCESto widok. Jeśli nie masz do niego dostępu, spróbuj wybrać, USER_SEQUENCESjeśli sekwencja znajduje się w Twoim domyślnym schemacie. (Nie będziesz potrzebować sequence_owner = '<sequence_owner>'klauzuli dla USER_SEQUENCES).
Ollie
15
LAST_NUMBERW ALL_SEQUENCESnie będzie to ostatni numer, że sesja została rzeczywiście podana i nie będzie to numer, który będzie zwrócony z wywołania sequence_name.nextvalw ogóle. Zakładając, że ustawiłeś sekwencję na CACHEwięcej niż 1 (domyślnie 20), LAST_NUMBERbędzie ostatnią liczbą znajdującą się w pamięci podręcznej. Nie ma gwarancji, że ten numer kiedykolwiek rzeczywiście zostanie nadany jakiejkolwiek sesji.
Justin Cave
2
ALTER SEQUENCE seq INCREMENT BY -1;będzie problemem, chyba że można zagwarantować , że żadna inna sesja nie zadzwoni seq.nextval. W przeciwnym razie sekwencja będzie rozdawać zduplikowane wartości, co zwykle nie jest tym, czego się chce.
Shannon Severance
1
OP powiedział: „To sprawdzenie po migracji danych”, więc założenie, że baza danych nie jest w powszechnym użyciu, nie jest trudne, ale może to stanowić problem, gdyby tak nie było.
Ollie
122

select MY_SEQ_NAME.currval from DUAL;

Pamiętaj, że działa to tylko wtedy, gdy biegałeś select MY_SEQ_NAME.nextval from DUAL;w bieżących sesjach.

RonK
źródło
1
Wielkie dzięki za odpowiedź. Muszę użyć tego w Boomi i szukałem rozwiązania w górę iw dół
ucząc się ...
0

Moja pierwotna odpowiedź była nieprawidłowa pod względem faktycznym i cieszę się, że została usunięta. Poniższy kod będzie działał w następujących warunkach a) wiesz, że nikt inny nie modyfikował sekwencji b) sekwencja została zmodyfikowana przez twoją sesję. W moim przypadku napotkałem podobny problem, gdy wywoływałem procedurę, która modyfikowała wartość i jestem pewien, że założenie jest prawdziwe.

SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;

Niestety, jeśli nie zmodyfikowałeś sekwencji w swojej sesji, uważam, że inni mają rację, twierdząc, że NEXTVAL jest jedyną drogą.

georgejo
źródło
0

To nie jest odpowiedź, tak naprawdę i wpisałbym ją jako komentarz, gdyby pytanie nie zostało zablokowane. To odpowiada na pytanie:

Dlaczego miałbyś tego chcieć?

Załóżmy, że masz tabelę z sekwencją jako kluczem podstawowym, a sekwencja jest generowana przez wyzwalacz wstawiania. Jeśli chcesz, aby sekwencja była dostępna do kolejnych aktualizacji rekordu, musisz mieć sposób na wyodrębnienie tej wartości.

Aby upewnić się, że otrzymałeś właściwy, możesz zawrzeć zapytanie INSERT i RonK w transakcji.

Zapytanie RonK:

select MY_SEQ_NAME.currval from DUAL;

W powyższym scenariuszu zastrzeżenie RonK nie ma zastosowania, ponieważ wstawianie i aktualizacja miałyby miejsce w tej samej sesji.

Ainsworth
źródło
0

Próbowałem również użyć CURRVAL, w moim przypadku, aby dowiedzieć się, czy jakiś proces wstawił nowe wiersze do jakiejś tabeli z tą sekwencją jako klucz podstawowy. Moje założenie było takie, że CURRVAL będzie najszybszą metodą. Ale a) CurrVal nie działa, po prostu otrzyma starą wartość, ponieważ jesteś w innej sesji Oracle, dopóki nie wykonasz NEXTVAL we własnej sesji. A b) a select max(PK) from TheTablejest również bardzo szybkie, prawdopodobnie dlatego, że PK jest zawsze indeksowana. Lubselect count(*) from TheTable . Wciąż eksperymentuję, ale oba SELECT wydają się szybkie.

Nie przeszkadza mi luka w sekwencji, ale w moim przypadku dużo myślałem o ankietach i nie chciałbym pomyśleć o bardzo dużych lukach. Zwłaszcza jeśli prosty SELECT byłby równie szybki.

Wniosek:

  • CURRVAL jest dość bezużyteczny, ponieważ nie wykrywa NEXTVAL z innej sesji, zwraca tylko to, co już wiedziałeś z poprzedniego NEXTVAL
  • SELECT MAX (...) FROM ... to dobre rozwiązanie, proste i szybkie, zakładając, że twoja sekwencja jest połączona z tą tabelą
Roland
źródło