Come reimpostare una sequenza in Oracle?


170

In PostgreSQL , posso fare qualcosa del genere:

ALTER SEQUENCE serial RESTART WITH 0;

Esiste un equivalente Oracle?


1
Dai un'occhiata a "Ripristini sequenza" qui .
Gerikson,

3
ATTENZIONE: tutto il codice seguente è valido solo per le sequenze inizialmente create con "incremento di 1". Se la sequenza originale è stata creata con un incremento! = 1; dopo aver applicato una delle procedure sopra, l'incremento sarà cambiato in 1! Il valore di incremento corretto da utilizzare può essere ottenuto dalla vista user_sequences.

Risposte:


153

Ecco una buona procedura per reimpostare qualsiasi sequenza su 0 dal guru Oracle Tom Kyte . Grande discussione sui pro e contro anche nei link sottostanti.

tkyte@TKYTE901.US.ORACLE.COM> 
create or replace
procedure reset_seq( p_seq_name in varchar2 )
is
    l_val number;
begin
    execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_val;

    execute immediate
    'alter sequence ' || p_seq_name || ' increment by -' || l_val || 
                                                          ' minvalue 0';

    execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_val;

    execute immediate
    'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
end;
/

Da questa pagina: SQL dinamico per ripristinare il valore della sequenza
Un'altra buona discussione è anche qui: Come ripristinare le sequenze?


@Dougman: ciao principiante .... nella risposta precedente perché menzioni nella clausola nell'ultimo invece esegui immediatamente 'select' || p_seq_name || '.nextval INTO l_val da dual';
Thiyagu ATR,

@Thiyagu: in PL / SQL questa è la sintassi quando si usa execute immediateper catturare l'output di una selezione che ritorna al massimo 1 riga. Ecco la documentazione sull'esecuzione immediata: docs.oracle.com/cd/B28359_01/appdev.111/b28370/…
Doug Porter,

@matra Non vedo uno scenario in cui si dovrebbe ripristinare una sequenza ed essere in un ambiente concorrente con altri utenti della stessa sequenza.
Ekevoo,

Perché è necessario selezionare la sequenza, perché non fare solo l'ultima riga'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
Goku,

100

Un vero riavvio non è possibile AFAIK . (Per favore correggimi se sbaglio!).

Tuttavia, se si desidera impostarlo su 0, è possibile eliminarlo e ricrearlo.

Se si desidera impostarlo su un valore specifico, è possibile impostare INCREMENT su un valore negativo e ottenere il valore successivo.

Cioè, se la sequenza è su 500, è possibile impostarla su 100 tramite

ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;

4
Solo una nota per le persone in PLSQL. Assicurati di aggiungere "limite 1;" o "rownum = 1" all'istruzione select, altrimenti puoi finire con nextVal un paio di volte e incrementare di -400 comunque molte volte.
user830914

1
Sequenza di errori .NEXTVAL scende al di sotto di MINVALUE e non può essere istanziato quando INCREMENT BY BY - <<nome_big>>
zloctb

47

Questo è il mio approccio:

  1. rilascia la sequenza
  2. ricrearlo

Esempio:

--Drop sequence

DROP SEQUENCE MY_SEQ;

-- Create sequence 

create sequence MY_SEQ
minvalue 1
maxvalue 999999999999999999999
start with 1
increment by 1
cache 20;

29
Basta essere consapevoli del fatto che il drop invaliderà tutti gli oggetti che dipendono da quella sequenza e dovranno essere ricompilati.
Doug Porter,

22
Dovrai inoltre concedere nuovamente le sovvenzioni concesse per selezionare dalla sequenza.
GreenGiant

37
alter sequence serial restart start with 1;

Questa funzionalità è stata aggiunta ufficialmente nel 18c, ma non è ufficialmente disponibile in 12.1.

È discutibilmente sicuro usare questa funzione non documentata in 12.1. Anche se la sintassi non è inclusa nella documentazione ufficiale , è generata dal pacchetto Oracle DBMS_METADATA_DIFF . L'ho usato più volte sui sistemi di produzione. Tuttavia, ho creato una richiesta di servizio Oracle e hanno verificato che non si tratta di un bug di documentazione, la funzionalità è davvero non supportata.

Nel 18c, la funzione non appare nella sintassi del linguaggio SQL, ma è inclusa nella Guida dell'amministratore del database .


Ehi @Jon, sono a conoscenza della funzione non documentata, tuttavia, non sapevo che fosse visibile nello script generato da DBMS_METADATA_DIFF. Potresti farmi sapere come hai generato lo script, quale procedura ecc.? Vorrei provare anche a provarlo.
Lalit Kumar B,

@LalitKumarB Mi sono imbattuto in quella funzione mentre rispondevo a questa domanda .
Jon Heller,

1
Aah, capito adesso. Grazie :-)
Lalit Kumar B

Immagino che questo sia stato implementato per supportare "alter table your_table edit (id generato di default su null come inizio dell'identità con valore limite);". Bello sapere che funziona anche su sequenze standard!
Oliver,

1
Nel caso in cui il valore minimo della sequenza sia maggiore 0 considera la scrittura... RESTART START WITH 0 MINVALUE 0
conceptdeluxe

33

Il mio approccio è un'estensione adolescenziale dell'esempio di Dougman .

Le estensioni sono ...

Passare il valore seme come parametro. Perché? Mi piace richiamare la cosa reimpostando la sequenza sull'ID massimo utilizzato in alcune tabelle . Finisco per chiamare questo proc da un altro script che esegue più chiamate per un intero gruppo di sequenze, ripristinando il valore successivo a un livello sufficientemente alto da non causare violazioni della chiave primaria in cui sto usando il valore della sequenza per un identificatore univoco.

Si onora anche la precedente minvalue . Può infatti spingere il valore successivo sempre più in alto se il valore p_val desiderato o il valore minimo esistente sono più alti del valore successivo corrente o calcolato.

Soprattutto, può essere chiamato per ripristinare un valore specificato e attendere fino a quando non viene visualizzata la procedura "correggi tutte le mie sequenze" del wrapper alla fine.

create or replace
procedure Reset_Sequence( p_seq_name in varchar2, p_val in number default 0)
is
  l_current number := 0;
  l_difference number := 0;
  l_minvalue user_sequences.min_value%type := 0;

begin

  select min_value
  into l_minvalue
  from user_sequences
  where sequence_name = p_seq_name;

  execute immediate
  'select ' || p_seq_name || '.nextval from dual' INTO l_current;

  if p_Val < l_minvalue then
    l_difference := l_minvalue - l_current;
  else
    l_difference := p_Val - l_current;
  end if;

  if l_difference = 0 then
    return;
  end if;

  execute immediate
    'alter sequence ' || p_seq_name || ' increment by ' || l_difference || 
       ' minvalue ' || l_minvalue;

  execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_difference;

  execute immediate
    'alter sequence ' || p_seq_name || ' increment by 1 minvalue ' || l_minvalue;
end Reset_Sequence;

Questa procedura è utile da sola, ma ora aggiungiamo un'altra che la chiama e specifica tutto a livello di programmazione con una convenzione di denominazione di sequenza e cercando il valore massimo utilizzato in una tabella / campo esistente ...

create or replace
procedure Reset_Sequence_to_Data(
  p_TableName varchar2,
  p_FieldName varchar2
)
is
  l_MaxUsed NUMBER;
BEGIN

  execute immediate
    'select coalesce(max(' || p_FieldName || '),0) from '|| p_TableName into l_MaxUsed;

  Reset_Sequence( p_TableName || '_' || p_Fieldname || '_SEQ', l_MaxUsed );

END Reset_Sequence_to_Data;

Ora stiamo cucinando con il gas!

La procedura sopra verificherà il valore massimo di un campo in una tabella, crea un nome di sequenza dalla coppia tabella / campo e richiama "Reset_Sequence" con quel valore massimo rilevato.

Il pezzo finale di questo puzzle e la ciliegina sulla torta viene dopo ...

create or replace
procedure Reset_All_Sequences
is
BEGIN

  Reset_Sequence_to_Data( 'ACTIVITYLOG', 'LOGID' );
  Reset_Sequence_to_Data( 'JOBSTATE', 'JOBID' );
  Reset_Sequence_to_Data( 'BATCH', 'BATCHID' );

END Reset_All_Sequences;

Nel mio database reale ci sono circa un centinaio di altre sequenze ripristinate tramite questo meccanismo, quindi ci sono altre 97 chiamate a Reset_Sequence_to_Data in quella procedura sopra.

Lo adoro? Lo odi? Indifferente?


2
Lo adoro. Aggiungerei una variabile per ottenere e salvare l'incremento in base al valore dalla tabella user_sequences. (Potrebbe non essere 1). Nota: potrebbe essere necessario utilizzare invece la tabella all_sequences. In questo caso potresti voler passare anche in sequenza_owner.
Harv,

1
Non posso votarti abbastanza. Questo è un problema piuttosto comune quando si affronta la migrazione dei dati, e questo è l'approccio migliore AFAIK se si è bloccati con le sequenze.
Dominique Eav,

1
È stato votato perché questo è un approccio eccellente. L'unico aspetto negativo è che può comportare un comportamento imprevedibile in un sistema RAC, dove l_currentpuò essere uno dei vari valori, a seconda del nodo in cui viene eseguito lo script; la riesecuzione dello script può comportare risultati diversi. Ho scoperto che se l'ho eseguito più volte alla fine si è stabilito su un valore particolare.
Jeffrey Kemp,

10

Il seguente script imposta la sequenza sul valore desiderato:

Data una sequenza appena creata denominata PCS_PROJ_KEY_SEQ e tabella PCS_PROJ:

BEGIN
   DECLARE
      PROJ_KEY_MAX       NUMBER := 0;
      PROJ_KEY_CURRVAL   NUMBER := 0;
   BEGIN

    SELECT MAX (PROJ_KEY) INTO PROJ_KEY_MAX FROM PCS_PROJ;
    EXECUTE IMMEDIATE 'ALTER SEQUENCE PCS_PROJ_KEY_SEQ INCREMENT BY ' || PROJ_KEY_MAX;
    SELECT PCS_PROJ_KEY_SEQ.NEXTVAL INTO PROJ_KEY_CURRVAL FROM DUAL;
    EXECUTE IMMEDIATE 'ALTER SEQUENCE PCS_PROJ_KEY_SEQ INCREMENT BY 1';

END;
END;
/

1
Hai dimenticato il segno meno nella tua prima istruzione DDL (inoltre, c'è una ENDparola chiave in più).
Priidu Neemre,

5

Questa procedura memorizzata riavvia la mia sequenza:

Create or Replace Procedure Reset_Sequence  
  is
  SeqNbr Number;
begin
   /*  Reset Sequence 'seqXRef_RowID' to 0    */
   Execute Immediate 'Select seqXRef.nextval from dual ' Into SeqNbr;
   Execute Immediate 'Alter sequence  seqXRef increment by - ' || TO_CHAR(SeqNbr) ;
   Execute Immediate 'Select seqXRef.nextval from dual ' Into SeqNbr;
   Execute Immediate 'Alter sequence  seqXRef increment by 1';
END;

/


+1: puoi anche parametrizzarlo per passare il nome della sequenza.
DCookie,

4

Esiste un altro modo per ripristinare una sequenza in Oracle: impostare le proprietà maxvaluee cycle. Quando la nextvalsequenza colpisce il maxvalue, se la cycleproprietà è impostata, ricomincerà da quella minvaluedella sequenza.

Il vantaggio di questo metodo rispetto all'impostazione di un negativo increment byè che la sequenza può continuare a essere utilizzata mentre il processo di ripristino è in esecuzione, riducendo la possibilità che si debba prendere una qualche forma di interruzione per eseguire il ripristino.

Il valore per maxvaluedeve essere maggiore della corrente nextval, quindi la procedura seguente include un parametro opzionale che consente un buffer nel caso in cui si acceda nuovamente alla sequenza tra la selezione nextvalnella procedura e l'impostazione della cycleproprietà.

create sequence s start with 1 increment by 1;

select s.nextval from dual
connect by level <= 20;

   NEXTVAL
----------
         1 
...
        20

create or replace procedure reset_sequence ( i_buffer in pls_integer default 0)
as
  maxval pls_integer;
begin

  maxval := s.nextval + greatest(i_buffer, 0); --ensure we don't go backwards!
  execute immediate 'alter sequence s cycle minvalue 0 maxvalue ' || maxval;
  maxval := s.nextval;
  execute immediate 'alter sequence s nocycle maxvalue 99999999999999';

end;
/
show errors

exec reset_sequence;

select s.nextval from dual;

   NEXTVAL
----------
         1 

La procedura così come è ancora consente la possibilità che un'altra sessione recuperi il valore 0, che potrebbe essere o meno un problema per te. Se lo è, puoi sempre:

  • Impostato minvalue 1nella prima modifica
  • Escludere il secondo nextvalrecupero
  • Spostare l'istruzione per impostare la nocycleproprietà in un'altra procedura, da eseguire in un secondo momento (supponendo che si desideri farlo).

3

Jezus, tutta questa programmazione per un solo riavvio dell'indice ... Forse sono un idiota, ma per pre-Oracle 12 (che ha una funzione di riavvio), cosa c'è di sbagliato in un simpel:

drop sequence blah;
create sequence blah 

?


2
Il problema principale con l'eliminazione di una sequenza è che perde i privilegi concessi su di essa.
Jon Heller,

1
Ok garantito, Jon. Principalmente anche ripristinarli costerà molto meno tempo di tutta quella programmazione. I buoni DBA di solito hanno degli script, quindi non dovrebbe essere un problema :-)
Lawrence,

2

1) Supponi di creare una SEQUENZA come mostrato di seguito:

CREATE SEQUENCE TESTSEQ
INCREMENT BY 1
MINVALUE 1
MAXVALUE 500
NOCACHE
NOCYCLE
NOORDER

2) Ora prendi i valori da SEQUENCE. Diciamo che ho recuperato quattro volte come mostrato di seguito.

SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual

3) Dopo aver eseguito sopra i quattro comandi, il valore di SEQUENCE sarà 4. Ora supponiamo di aver reimpostato il valore di SEQUENCE su 1. Seguire i seguenti passi. Seguire tutti i passaggi nello stesso ordine mostrato di seguito:

  1. ALTER SEQUENCE TESTSEQ INCREMENT BY -3;
  2. SELECT TESTSEQ.NEXTVAL FROM dual
  3. ALTER SEQUENCE TESTSEQ INCREMENT BY 1;
  4. SELECT TESTSEQ.NEXTVAL FROM dual

2

Modificare il valore INCREMENT della sequenza, aumentarlo e quindi ripristinarlo è piuttosto indolore, inoltre si ha il vantaggio di non dover ristabilire tutte le sovvenzioni come se si fosse lasciato cadere / ricreato la sequenza.


2

Creo un blocco per ripristinare tutte le mie sequenze:

DECLARE
    I_val number;
BEGIN
    FOR US IN
        (SELECT US.SEQUENCE_NAME FROM USER_SEQUENCES US)
    LOOP
        execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
        execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by -' || l_val || ' minvalue 0';
        execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
        execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by 1 minvalue 0';
    END LOOP;
END;

2

Ecco una procedura più solida per modificare il valore successivo restituito da una sequenza, e molto altro ancora.

  • Innanzitutto protegge dagli attacchi di SQL injection poiché nessuna delle stringhe passate viene utilizzata per creare direttamente una delle istruzioni SQL dinamiche,
  • In secondo luogo impedisce di impostare il valore della sequenza successiva al di fuori dei limiti dei valori di sequenza min o max. Il next_valuesarà! = min_valueE tra il min_valuee max_value.
  • Terzo, increment_bydurante la pulizia tiene conto dell'impostazione corrente (o proposta) e di tutte le altre impostazioni della sequenza.
  • In quarto luogo, tutti i parametri tranne il primo sono facoltativi e, se non diversamente specificato, assumono l'impostazione di sequenza corrente come valori predefiniti. Se non vengono specificati parametri opzionali, non viene intrapresa alcuna azione.
  • Infine, se provi a modificare una sequenza che non esiste (o non è di proprietà dell'utente corrente) genererà un ORA-01403: no data founderrore.

Ecco il codice:

CREATE OR REPLACE PROCEDURE alter_sequence(
    seq_name      user_sequences.sequence_name%TYPE
  , next_value    user_sequences.last_number%TYPE := null
  , increment_by  user_sequences.increment_by%TYPE := null
  , min_value     user_sequences.min_value%TYPE := null
  , max_value     user_sequences.max_value%TYPE := null
  , cycle_flag    user_sequences.cycle_flag%TYPE := null
  , cache_size    user_sequences.cache_size%TYPE := null
  , order_flag    user_sequences.order_flag%TYPE := null)
  AUTHID CURRENT_USER
AS
  l_seq user_sequences%rowtype;
  l_old_cache user_sequences.cache_size%TYPE;
  l_next user_sequences.min_value%TYPE;
BEGIN
  -- Get current sequence settings as defaults
  SELECT * INTO l_seq FROM user_sequences WHERE sequence_name = seq_name;

  -- Update target settings
  l_old_cache := l_seq.cache_size;
  l_seq.increment_by := nvl(increment_by, l_seq.increment_by);
  l_seq.min_value    := nvl(min_value, l_seq.min_value);
  l_seq.max_value    := nvl(max_value, l_seq.max_value);
  l_seq.cycle_flag   := nvl(cycle_flag, l_seq.cycle_flag);
  l_seq.cache_size   := nvl(cache_size, l_seq.cache_size);
  l_seq.order_flag   := nvl(order_flag, l_seq.order_flag);

  IF next_value is NOT NULL THEN
    -- Determine next value without exceeding limits
    l_next := LEAST(GREATEST(next_value, l_seq.min_value+1),l_seq.max_value);

    -- Grab the actual latest seq number
    EXECUTE IMMEDIATE
        'ALTER SEQUENCE '||l_seq.sequence_name
            || ' INCREMENT BY 1'
            || ' MINVALUE '||least(l_seq.min_value,l_seq.last_number-l_old_cache)
            || ' MAXVALUE '||greatest(l_seq.max_value,l_seq.last_number)
            || ' NOCACHE'
            || ' ORDER';
    EXECUTE IMMEDIATE 
      'SELECT '||l_seq.sequence_name||'.NEXTVAL FROM DUAL'
    INTO l_seq.last_number;

    l_next := l_next-l_seq.last_number-1;

    -- Reset the sequence number
    IF l_next <> 0 THEN
      EXECUTE IMMEDIATE 
        'ALTER SEQUENCE '||l_seq.sequence_name
            || ' INCREMENT BY '||l_next
            || ' MINVALUE '||least(l_seq.min_value,l_seq.last_number)
            || ' MAXVALUE '||greatest(l_seq.max_value,l_seq.last_number)
            || ' NOCACHE'
            || ' ORDER';
      EXECUTE IMMEDIATE 
        'SELECT '||l_seq.sequence_name||'.NEXTVAL FROM DUAL'
      INTO l_next;
    END IF;
  END IF;

  -- Prepare Sequence for next use.
  IF COALESCE( cycle_flag
             , next_value
             , increment_by
             , min_value
             , max_value
             , cache_size
             , order_flag) IS NOT NULL
  THEN
    EXECUTE IMMEDIATE 
      'ALTER SEQUENCE '||l_seq.sequence_name
          || ' INCREMENT BY '||l_seq.increment_by
          || ' MINVALUE '||l_seq.min_value
          || ' MAXVALUE '||l_seq.max_value
          || CASE l_seq.cycle_flag
             WHEN 'Y' THEN ' CYCLE' ELSE ' NOCYCLE' END
          || CASE l_seq.cache_size
             WHEN 0 THEN ' NOCACHE'
             ELSE ' CACHE '||l_seq.cache_size END
          || CASE l_seq.order_flag
             WHEN 'Y' THEN ' ORDER' ELSE ' NOORDER' END;
  END IF;
END;

2

Nel mio progetto, una volta è successo che qualcuno ha inserito manualmente i record senza usare la sequenza, quindi devo reimpostare manualmente il valore della sequenza, per il quale ho scritto sotto lo snippet di codice sql:

declare
max_db_value number(10,0);
cur_seq_value number(10,0);
counter number(10,0);
difference number(10,0);
dummy_number number(10);

begin

-- enter table name here
select max(id) into max_db_value from persons;
-- enter sequence name here
select last_number into cur_seq_value from user_sequences where  sequence_name = 'SEQ_PERSONS';

difference  := max_db_value - cur_seq_value;

 for counter in 1..difference
 loop
    -- change sequence name here as well
    select SEQ_PERSONS.nextval into dummy_number from dual;
 end loop;
end;

Si noti che il codice sopra funzionerà se la sequenza è in ritardo.


1

È possibile utilizzare l'opzione CICLO, mostrata di seguito:

CREATE SEQUENCE test_seq
MINVALUE 0
MAXVALUE 100
START WITH 0
INCREMENT BY 1
CYCLE;

In questo caso, quando la sequenza raggiunge MAXVALUE (100), verrà riciclata su MINVALUE (0).

Nel caso di una sequenza decrementata, la sequenza verrebbe riciclata in MAXVALUE.


1
Per i downvoter (che non vedranno mai questo commento): l'attributo CYCLE è esattamente quello che ho usato per realizzare un reset della sequenza. Il fatto che il ripristino sia automatico non significa che non raggiunga l'obiettivo - OP non ha specificato che il ripristino doveva essere per una sequenza preesistente !
Jeromy francese

1

Ecco come fare in modo che tutte le sequenze di incremento automatico corrispondano ai dati effettivi:

  1. Creare una procedura per applicare il valore successivo come già descritto in questo thread:

    CREATE OR REPLACE PROCEDURE Reset_Sequence(
        P_Seq_Name IN VARCHAR2,
        P_Val      IN NUMBER DEFAULT 0)
    IS
      L_Current    NUMBER                      := 0;
      L_Difference NUMBER                      := 0;
      L_Minvalue User_Sequences.Min_Value%Type := 0;
    BEGIN
      SELECT Min_Value
      INTO L_Minvalue
      FROM User_Sequences
      WHERE Sequence_Name = P_Seq_Name;
      EXECUTE Immediate 'select ' || P_Seq_Name || '.nextval from dual' INTO L_Current;
      IF P_Val        < L_Minvalue THEN
        L_Difference := L_Minvalue - L_Current;
      ELSE
        L_Difference := P_Val - L_Current;
      END IF;
      IF L_Difference = 0 THEN
        RETURN;
      END IF;
      EXECUTE Immediate 'alter sequence ' || P_Seq_Name || ' increment by ' || L_Difference || ' minvalue ' || L_Minvalue;
      EXECUTE Immediate 'select ' || P_Seq_Name || '.nextval from dual' INTO L_Difference;
      EXECUTE Immediate 'alter sequence ' || P_Seq_Name || ' increment by 1 minvalue ' || L_Minvalue;
    END Reset_Sequence;
  2. Creare un'altra procedura per riconciliare tutte le sequenze con il contenuto effettivo:

    CREATE OR REPLACE PROCEDURE RESET_USER_SEQUENCES_TO_DATA
    IS
      STMT CLOB;
    BEGIN
      SELECT 'select ''BEGIN'' || chr(10) || x || chr(10) || ''END;'' FROM (select listagg(x, chr(10)) within group (order by null) x FROM ('
        || X
        || '))'
      INTO STMT
      FROM
        (SELECT LISTAGG(X, ' union ') WITHIN GROUP (
        ORDER BY NULL) X
        FROM
          (SELECT CHR(10)
            || 'select ''Reset_Sequence('''''
            || SEQ_NAME
            || ''''','' || coalesce(max('
            || COL_NAME
            || '), 0) || '');'' x from '
            || TABLE_NAME X
          FROM
            (SELECT TABLE_NAME,
              REGEXP_SUBSTR(WTEXT, 'NEW\.(\S*) IS NULL',1,1,'i',1) COL_NAME,
              REGEXP_SUBSTR(BTEXT, '(\.|\s)([a-z_]*)\.nextval',1,1,'i',2) SEQ_NAME
            FROM USER_TRIGGERS
            LEFT JOIN
              (SELECT NAME BNAME,
                TEXT BTEXT
              FROM USER_SOURCE
              WHERE TYPE = 'TRIGGER'
              AND UPPER(TEXT) LIKE '%NEXTVAL%'
              )
            ON BNAME = TRIGGER_NAME
            LEFT JOIN
              (SELECT NAME WNAME,
                TEXT WTEXT
              FROM USER_SOURCE
              WHERE TYPE = 'TRIGGER'
              AND UPPER(TEXT) LIKE '%IS NULL%'
              )
            ON WNAME             = TRIGGER_NAME
            WHERE TRIGGER_TYPE   = 'BEFORE EACH ROW'
            AND TRIGGERING_EVENT = 'INSERT'
            )
          )
        ) ;
      EXECUTE IMMEDIATE STMT INTO STMT;
      --dbms_output.put_line(stmt);
      EXECUTE IMMEDIATE STMT;
    END RESET_USER_SEQUENCES_TO_DATA;

APPUNTI:

  1. La procedura estrae i nomi dal codice trigger e non dipende dalle convenzioni di denominazione
  2. Per controllare il codice generato prima dell'esecuzione, cambia i commenti sulle ultime due righe

1

Faccio un'alternativa che l'utente non ha bisogno di conoscere i valori, il sistema ottiene e usa le variabili per aggiornare.

--Atualizando sequence da tabela SIGA_TRANSACAO, pois está desatualizada
DECLARE
 actual_sequence_number INTEGER;
 max_number_from_table INTEGER;
 difference INTEGER;
BEGIN
 SELECT [nome_da_sequence].nextval INTO actual_sequence_number FROM DUAL;
 SELECT MAX([nome_da_coluna]) INTO max_number_from_table FROM [nome_da_tabela];
 SELECT (max_number_from_table-actual_sequence_number) INTO difference FROM DUAL;
IF difference > 0 then
 EXECUTE IMMEDIATE CONCAT('alter sequence [nome_da_sequence] increment by ', difference);
 --aqui ele puxa o próximo valor usando o incremento necessário
 SELECT [nome_da_sequence].nextval INTO actual_sequence_number from dual;
--aqui volta o incremento para 1, para que futuras inserções funcionem normalmente
 EXECUTE IMMEDIATE 'ALTER SEQUENCE [nome_da_sequence] INCREMENT by 1';
 DBMS_OUTPUT.put_line ('A sequence [nome_da_sequence] foi atualizada.');
ELSE
 DBMS_OUTPUT.put_line ('A sequence [nome_da_sequence] NÃO foi atualizada, já estava OK!');
END IF;
END;

-1

Procedura memorizzata che ha funzionato per me

create or replace
procedure reset_sequence( p_seq_name in varchar2, tablename in varchar2 )
is
    l_val number;
    maxvalueid number;
begin
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'select max(id) from ' || tablename INTO maxvalueid;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by -' || l_val || ' minvalue 0';
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by '|| maxvalueid ||' minvalue 0';  
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
end;

Come utilizzare la procedura memorizzata:

execute reset_sequence('company_sequence','company');
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.