web-dev-qa-db-fra.com

Le meilleur moyen de réinitialiser une séquence Oracle à la valeur suivante dans une colonne existante?

Pour une raison quelconque, des personnes dans le passé ont inséré des données sans utiliser sequence.NEXTVAL. Ainsi, lorsque je vais utiliser sequence.NEXTVAL afin de remplir une table, j'obtiens une violation de PK, car ce numéro est déjà utilisé dans la table.

Comment mettre à jour la prochaine valeur pour qu'elle soit utilisable? En ce moment, j'insère encore et encore jusqu'à ce qu'il réussisse (INSERT INTO tbl (pk) VALUES (sequence.NEXTVAL)), et cela synchronise la valeur suivante.

41
Cade Roux

Ces deux procédures me permettent de réinitialiser la séquence et de réinitialiser la séquence en fonction des données d'une table (excuses pour les conventions de codage utilisées par ce client):

CREATE OR REPLACE PROCEDURE SET_SEQ_TO(p_name IN VARCHAR2, p_val IN NUMBER)
AS
   l_num   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   -- Added check for 0 to avoid "ORA-04002: INCREMENT must be a non-zero integer"
   IF (p_val - l_num - 1) != 0
   THEN
      EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by ' || (p_val - l_num - 1) || ' minvalue 0';
   END IF;

   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by 1 ';

   DBMS_OUTPUT.put_line('Sequence ' || p_name || ' is now at ' || p_val);
END;

CREATE OR REPLACE PROCEDURE SET_SEQ_TO_DATA(seq_name IN VARCHAR2, table_name IN VARCHAR2, col_name IN VARCHAR2)
AS
   nextnum   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'SELECT MAX(' || col_name || ') + 1 AS n FROM ' || table_name INTO nextnum;

   SET_SEQ_TO(seq_name, nextnum);
END;
16
Cade Roux

Vous pouvez augmenter temporairement la taille du cache et effectuer une sélection fictive, puis réinitialiser la taille du cache à 1. Ainsi, par exemple

ALTER SEQUENCE mysequence INCREMENT BY 100;

select mysequence.nextval from dual;

ALTER SEQUENCE mysequence INCREMENT BY 1;
78
Basanth Roy

Si vous pouvez compter sur une période de temps où la table est dans un état stable sans nouvelle insertion, cela devrait le faire (non testé):

DECLARE
  last_used  NUMBER;
  curr_seq   NUMBER;
BEGIN
  SELECT MAX(pk_val) INTO last_used FROM your_table;

  LOOP
    SELECT your_seq.NEXTVAL INTO curr_seq FROM dual;
    IF curr_seq >= last_used THEN EXIT;
    END IF;
  END LOOP;
END;

Cela vous permet de synchroniser la séquence avec la table, sans supprimer/recréer/ré-accorder la séquence. Il n'utilise pas non plus de DDL, donc aucune validation implicite n'est effectuée. Bien sûr, vous allez devoir traquer et gifler les gens qui insistent pour ne pas utiliser la séquence pour remplir la colonne ...

12
DCookie

Dans mon cas, j'ai une séquence appelée PS_LOG_SEQ Qui avait un LAST_NUMBER = 3920.

J'ai ensuite importé des données de PROD sur ma machine locale et inséré dans la table PS_LOG. Les données de production avaient plus de 20000 Lignes, la dernière LOG_ID (clé primaire) étant 20070. Après l'importation, j'ai essayé d'insérer de nouvelles lignes dans ce tableau mais lors de l'enregistrement, j'ai eu une exception comme celle-ci:

ORA-00001: unique constraint (LOG.PS_LOG_PK) violated

Cela a sûrement à voir avec la séquence PS_LOG_SEQ Associée à la table PS_LOG. Le LAST_NUMBER Entrait en collision avec des données que j'avais importées qui avaient déjà utilisé la prochaine valeur d'ID du PS_LOG_SEQ.

Pour résoudre ce problème, j'ai utilisé cette commande pour mettre à jour la séquence vers la dernière\max(LOG_ID) + 1:

alter sequence PS_LOG_SEQ restart start with 20071;

Cette commande a réinitialisé la valeur LAST_NUMBER Et j'ai pu ensuite insérer de nouvelles lignes dans le tableau. Plus de collision. :)

Remarque: cette commande alter sequence est nouvelle dans Oracle 12c.

10
Leniel Maccaferri

Avec Oracle 10.2g:

select  level, sequence.NEXTVAL
from  dual 
connect by level <= (select max(pk) from tbl);

définira la valeur de séquence actuelle au maximum (pk) de votre table (c'est-à-dire que le prochain appel à NEXTVAL vous donnera le bon résultat); si vous utilisez Toad, appuyez sur F5 pour exécuter l'instruction, et non F9, qui affiche la sortie (arrêtant ainsi l'incrément après, généralement, 500 lignes). Bon côté: cette solution est uniquement DML, pas DDL. Uniquement SQL et pas PL-SQL. Mauvais côté: cette solution imprime max (pk) lignes de sortie, c'est-à-dire est généralement plus lente que la solution ALTER SEQUENCE.

9
tech