Oracle 9 - Réinitialisation de la séquence pour correspondre à l'état de la table

StackOverflow https://stackoverflow.com/questions/1426647

  •  07-07-2019
  •  | 
  •  

Question

J'ai une séquence utilisée pour ensemencer mes clés primaires (basées sur un entier) dans une table oracle.

Il apparaît que cette séquence n'a pas toujours été utilisée pour insérer de nouvelles valeurs dans le tableau. Comment retrouver la séquence en phase avec les valeurs réelles du tableau?

Était-ce utile?

La solution

Si ID est le nom de votre colonne de PK et si PK_SEQ est le nom de votre séquence:

  1. Trouvez la valeur du PK le plus élevé en SELECT MAX (ID) FROM nomTable

  2. Trouvez la valeur du prochain PK_SEQ en     SÉLECTIONNEZ PK_SEQ.NEXTVAL FROM DUAL

  3. Si n ° 2 > # 1 alors rien ne doit être     fait, en supposant que vous traitez ces     des valeurs en tant que vraies clés de substitution
  4. Sinon, modifiez la séquence en     passer au max ID par ALTER SEQUENCE     PK_SEQ INCREMENT BY [# 1 valeur - # 2     valeur]
  5. Bump la séquence par SELECT     PK_SEQ.NEXTVAL FROM DUAL

  6. Réinitialiser la valeur d'incrément de séquence     à 1 par ALTER SEQUENCE PK_SEQ     INCRÉMENT DE 1

Tout cela suppose que vous n'ayez pas de nouvelles insertions dans la table pendant que vous le faites ...

Autres conseils

En bref, jouez:

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

Vous pouvez obtenir la valeur de séquence maximale utilisée dans votre tableau, faire le calcul et mettre à jour la séquence en conséquence.

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;

J'ai créé ce script car je n'ai pas trouvé de script en ligne qui définisse de manière dynamique toutes mes séquences sur l'ID actuel le plus élevé. Testé sur 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;

Dans certains cas, il vous sera peut-être plus facile d'obtenir simplement la valeur maximale actuelle, puis

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

L'application sera brisée après que vous ayez effectué le largage. Mais cela empêchera quiconque d'insérer des lignes pendant cette période et la création d'une séquence est rapide. Assurez-vous de recréer toutes les attributions de la séquence car celles-ci seront supprimées lors de la séquence. Et vous voudrez peut-être recompiler manuellement les fichiers plsql qui dépendent de la séquence.

Ajout jusqu’à https://stackoverflow.com/a/15929548/1737973 , mais sans recourir à SEQUENCENAME.NEXTVAL ne doit donc pas donner lieu à une position unique:

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;

Clause de non-responsabilité: si la séquence utilise la mise en cache ( all_sequences.cache_size définie sur une valeur supérieure à 0), vous souhaiterez probablement en tenir compte dans la Calculer la différence < em> step.

documentation Oracle pour toutes les séquences ... .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top