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?

Foi útil?

Solução

Se o ID é o nome da sua coluna PK e PK_SEQ é o nome da sua sequência:

  1. Encontre o valor da maior PK por Select max (ID) FROM tableName

  2. Encontre o valor do próximo PK_SEQ por SELECIONAR PK_SEQ.NEXTVAL FROM DUAL

  3. Se # 2> # 1 não precisa de nada, em seguida, ser fazer, supondo que você tratá-los valores como chaves verdadeiro substituto
  4. 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]
  5. Bump a seqüência pelo comando SELECT PK_SEQ.NEXTVAL FROM DUAL

  6. 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

documentação do Oracle para all sequences ... .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top