2009-09-15 19 views
15

Mam sekwencję używaną do wysiewu moich kluczy głównych (opartych na Integer) w tabeli Oracle.Oracle 9 - Resetowanie sekwencji, aby dopasować stan tabeli

Wygląda na to, że ta sekwencja nie zawsze była używana do wstawiania nowych wartości do tabeli. Jak uzyskać sekwencję z powrotem z rzeczywistymi wartościami w tabeli?

Odpowiedz

14

Jeśli ID to nazwa kolumny PK i PK_SEQ jest nazwa sekwencji:

  1. Znajdź wartość najwyższą PK przez SELECT MAX (ID) z TableName

  2. Znajdź wartość następnego PK_SEQ przez SELECT FROM DUAL PK_SEQ.NEXTVAL

  3. Jeśli # 2> # 1 to nic nie musi być zrobić, zakładając, że traktują te Wartości jako prawdziwe przyciski zastępcze
  4. przeciwnym razie zmiany sekwencji do skokiem max ID alter SEKWENCJA PK_SEQ inkrementowany [# 1, # 2 - wartości wartość]
  5. uderzać o sekwencji SELECT PK_SEQ.NEXTVAL od Podwójnej

  6. Reset wartość przyrostu sekwencji do 1 Alter sEKWENCJI PK_SEQ zwiększane o 1

To wszystko zakłada, że ​​nie ma nowych wkładek do stołu, gdy robisz to ...

+0

Mam problem z jak zrobić krok 3, próbowałem różnych składni, ale nie mogę go uruchomić – AJM

+2

Celem kroku 3 jest po prostu porównać największą wartość PK do następnej wartości sekwencji. Na przykład, jeśli SELECT z kroku 1 dało wynik 100, a SELECT z kroku 2 dało wynik 90, co oznacza, że ​​masz "skok" 11 sekwencji. Gdy zmienisz sekwencję w kroku 4, SELECT w kroku 5 przesunie wartości sekwencji 10 do 100. Po tym jak inkrement zostanie skasowany w kroku 6, następne "SELECT PK_SEQ.NEXTVAL FROM DUAL" da ci 101. – dpbradley

+0

In krok 4 Nie mogę uzyskać składni, aby wykonać odejmowanie w klauzuli Przyrost za pomocą. Próbowałem [a-b] a-b i selecr a-b od dual, ale nie z żadnym sukcesem. – AJM

11

W skrócie, gra go:

-- Current sequence value is 1000 

ALTER SEQUENCE x INCREMENT BY -999; 
Sequence altered. 

SELECT X.NEXTVAL FROM DUAL; 
1 

ALTER SEQUENCE x INCREMENT BY 1; 
Sequence altered. 

Można uzyskać maksymalną wartość sekwencja stosowana wewnątrz tabeli, do matematyki i zaktualizuj sekwencję odpowiednio.

+0

Jak to pomaga. Jeśli maksymalny identyfikator w tabeli to 624. W jaki sposób powyższe ustawienie poprawnie ustawia seq? – ginalster

0

w niektórych przypadkach może się okazać, że łatwiej po prostu uzyskać bieżącą wartość maksymalną, a następnie

drop sequence x; 
create sequence x start with {current max + 1}; 

Aplikacja zostanie zerwana po upuszczeniu. Ale to nie pozwoli nikomu na wstawianie wierszy w tym okresie, a tworzenie sekwencji jest szybkie. Upewnij się, że odtwarzasz wszystkie granty w sekwencji, ponieważ zostaną one upuszczone, gdy sekwencja jest. I możesz chcieć ręcznie przekompilować dowolny plik plsql, który zależy od sekwencji.

+2

@Jim - Uniknęłabym upuszczenia dowolnego obiektu db, jeśli istnieje alternatywa. Upuszczenie sekwencji niekoniecznie uniemożliwi wstawienia do tabeli, które nie odwołują się do sekwencji. Jak podkreślasz, masz również dodatkową pracę polegającą na przechwytywaniu grantów i rekompilacji zależnych obiektów. – dpbradley

8
Declare 
    difference INTEGER; 
    sqlstmt varchar2(255); 
    sequenceValue Number; 
begin 
sqlstmt := 'ALTER SEQUENCE YOURSEQUENCE INCREMENT BY '; 
select YOURSEQUENCE.NEXTVAL into sequenceValue from dual; 
select (nvl(Max(YOURID),0) - sequenceValue)+1 into difference from YOURTABLE; 
if difference > 0 then 
    EXECUTE IMMEDIATE sqlstmt || difference; 
    select YOURSEQUENCE.NEXTVAL INTO sequenceValue from dual; 
    EXECUTE IMMEDIATE sqlstmt || 1; 
end if; 
end; 
+1

To stawia to 1 powyżej, gdzie powinno być ... – Worthy7

+0

Myślę, że dzieje się tak z powodu 'wybrania YOURSEQUENCE.NEXTVAL na sequenceValue z dual;' w linii 7, możesz sprawdzić alternatywę dla mojej odpowiedzi na [https://stackoverflow.com/a/45542069/1737973](https://stackoverflow.com/a/45542069/1737973), który pobiera 'all_sequences.last_number WHERE nazwa_sekwencji = 'YOURSYKONDĘ'' zamiast' YOURSQUENCE.NEXTVAL', prawdopodobnie żądana wartość buforowania buforowanej wartości sekwencji jest wyłączona_. – uprego

4

Zrobiłem ten skrypt jako nie znalazłem skrypt internetowy, który dynamicznie ustawia wszystkie moje sekwencje do obecnego najwyższego ID. Testowane w Oracle 11.2.0.4.

DECLARE 
    difference   INTEGER; 
    sqlstmt   VARCHAR2(255) ; 
    sqlstmt2   VARCHAR2(255) ; 
    sqlstmt3   VARCHAR2(255) ; 
    sequenceValue  NUMBER; 
    sequencename  VARCHAR2(30) ; 
    sequencelastnumber INTEGER; 
    CURSOR allseq 
    IS 
    SELECT sequence_name, last_number FROM user_sequences ORDER BY sequence_name; 
BEGIN 
    DBMS_OUTPUT.enable(32000) ; 
    OPEN allseq; 
    LOOP 
    FETCH allseq INTO sequencename, sequencelastnumber; 
    EXIT 
    WHEN allseq%NOTFOUND; 
    sqlstmt := 'ALTER SEQUENCE ' || sequencename || ' INCREMENT BY '; 
    --Assuming: <tablename>_id is <sequencename> 
    sqlstmt2 := 'select (nvl(Max(ID),0) - :1)+1 from ' || SUBSTR(sequencename, 1, LENGTH(sequencename) - 3) ; 
    --DBMS_OUTPUT.PUT_LINE(sqlstmt2); 
    --Attention: makes use of user_sequences.last_number --> possible cache problems! 
    EXECUTE IMMEDIATE sqlstmt2 INTO difference USING sequencelastnumber; 
    IF difference > 0 THEN 
     DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || difference) ; 
     EXECUTE IMMEDIATE sqlstmt || difference; 
     sqlstmt3 := 'SELECT ' || sequencename ||'.NEXTVAL from dual'; 
     DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt3 || ' INTO sequenceValue') ; 
     EXECUTE IMMEDIATE sqlstmt3 INTO sequenceValue; 
     DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || 1) ; 
     EXECUTE IMMEDIATE sqlstmt || 1; 
     DBMS_OUTPUT.PUT_LINE('') ; 
    END IF; 
    END LOOP; 
    CLOSE allseq; 
END; 
0

dodanie do https://stackoverflow.com/a/15929548/1737973, bez uciekania się do SEQUENCENAME.NEXTVAL dlatego nie powodując jednej pozycji ponad powinien być:

DECLARE 
    difference INTEGER; 
    alter_sequence_statement VARCHAR2 (255); 
    sequence_value NUMBER; 
BEGIN 
    -- Base for the statement that will set the sequence value. 
    alter_sequence_statement := 
     'ALTER SEQUENCE SEQUENCENAME INCREMENT BY '; 

    -- Fetch current last sequence value used. 
    SELECT 
    -- You could maybe want to make some further computations just 
    -- below if the sequence is using caching. 
    last_number 
    INTO sequence_value 
    FROM all_sequences 
    WHERE sequence_owner = 'SEQUENCEOWNER' AND sequence_name = 'SEQUENCENAME'; 

    -- Compute the difference. 
    SELECT max(id) - sequence_value + 1 INTO difference 
    FROM SCHEMANAME.TABLENAME; 

    IF difference <> 0 THEN 
    -- Set the increment to a big offset that puts the sequence near 
    -- its proper value. 
    EXECUTE IMMEDIATE alter_sequence_statement || difference; 

    -- This 'sequence_value' will be ignored, on purpose. 
    SELECT SEQUENCENAME.NEXTVAL INTO sequence_value FROM dual; 

    -- Resume the normal pace of incrementing one by one. 
    EXECUTE IMMEDIATE alter_sequence_statement || 1; 
    END IF; 
END; 

Uwaga: jeżeli sekwencja jest z bufora (all_sequences.cache_size zestaw do większy 0) prawdopodobnie chcesz wziąć to pod uwagę w kroku Oblicz różnicę .

Oracle documentation for all sequences....

+0

No cóż, przykro mi, że to jest dla Oracle 11, nie wiem, czy to może działać w Oracle 9 bez zmian. – uprego

Powiązane problemy