A Oracle 9 - redefinição Sequence para coincidir com o estado da tabela
Pergunta
Eu tenho uma seqüência usados ??para semear meus (com base Integer) chaves primárias em uma tabela Oracle.
Parece essa seqüência nem sempre foi usado para inserir novos valores na tabela. Como faço para obter a volta seqüência em sintonia com os valores reais na tabela?
Solução
Se o ID é o nome da sua coluna PK e PK_SEQ é o nome da sua sequência:
-
Encontre o valor da maior PK por Select max (ID) FROM tableName
-
Encontre o valor do próximo PK_SEQ por SELECIONAR PK_SEQ.NEXTVAL FROM DUAL
- Se # 2> # 1 não precisa de nada, em seguida, ser fazer, supondo que você tratá-los valores como chaves verdadeiro substituto
- Caso contrário, a sequência para alterar saltar para o ID máximo por ALTER SEQUENCE PK_SEQ INCREMENT BY [# 1 valor - # 2 valor]
-
Bump a seqüência pelo comando SELECT PK_SEQ.NEXTVAL FROM DUAL
-
Redefinir o valor de incremento seqüência para 1 por alteram a sequência PK_SEQ INCREMENT BY 1
Isso tudo pressupõe que você não tem novas inserções na tabela enquanto você está fazendo isso ...
Outras dicas
Em suma, jogo-o:
-- 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.
Você pode obter o valor da seqüência max usado dentro de sua mesa, fazer a matemática, e atualizar a seqüência de conformidade.
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;
Eu fiz este script como eu não encontrei um script em linha que define dinamicamente todas minhas seqüências para a corrente mais alta ID. Testado no 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;
Em alguns casos, você pode achar que é mais fácil simplesmente obter o valor máximo atual e, em seguida,
drop sequence x;
create sequence x start with {current max + 1};
O aplicativo será quebrado depois de fazer a queda. Mas isso vai manter ninguém de inserir linhas durante esse período, e criando uma seqüência é rápido. Certifique-se de recriar quaisquer concessões na sequência uma vez que aqueles serão descartados quando a seqüência é. E você pode querer recompilar manualmente qualquer plsql que depende da seqüência.
Adicionando até https://stackoverflow.com/a/15929548/1737973 , mas sem recorrer a SEQUENCENAME.NEXTVAL
daí não resultando em uma posição sobre o que deve ser:
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;
Disclaimer:. Se a sequência está usando (conjunto all_sequences.cache_size
para maior que 0) caching provavelmente você está querendo levá-lo em consideração no Compute a diferença passo