188

PostgreSQLでは、次のようなことができます。

ALTER SEQUENCE serial RESTART WITH 0;

Oracleに相当するものはありますか?

4

18 に答える 18

162

オラクルの第一人者であるTom Kyteによる、任意のシーケンスを 0 にリセットするための適切な手順を次に示します。以下のリンクでも、長所と短所に関する素晴らしい議論が行われています。

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;
/

このページから:シーケンス値をリセットする動的 SQL
別の良い議論もここにあります:シーケンスをリセットする方法?

于 2008-09-18T15:34:52.270 に答える
116

真の再起動は可能ではありませんAFAIK。(私が間違っている場合は修正してください!)。

ただし、0 に設定したい場合は、削除して再作成するだけです。

特定の値に設定したい場合は、INCREMENT を負の値に設定して次の値を取得できます。

つまり、シーケンスが 500 の場合、次の方法で 100 に設定できます。

ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;
于 2008-09-09T09:46:29.030 に答える
51

これが私のアプローチです:

  1. シーケンスをドロップします
  2. それを作り直す

例:

--Drop sequence

DROP SEQUENCE MY_SEQ;

-- Create sequence 

create sequence MY_SEQ
minvalue 1
maxvalue 999999999999999999999
start with 1
increment by 1
cache 20;
于 2010-05-19T14:56:29.633 に答える
34

私のアプローチは、Dougman の例を少し拡張したものです。

拡張子は...

シード値をパラメーターとして渡します。なんで?シーケンスをいくつかのテーブルで使用されている最大 IDにリセットすることを呼び出すのが好きです。シーケンス全体に対して複数の呼び出しを実行する別のスクリプトからこのプロシージャを呼び出すことになり、nextval を、一意の識別子にシーケンスの値を使用している場合に主キー違反を引き起こさないほど十分に高いレベルにリセットします。

また、以前のminvalueを尊重します。実際には、目的のp_valまたは既存の最小値が現在の値または計算された次の値よりも高い場合、次の値をさらに高くプッシュする可能性があります。

何よりも、指定された値にリセットするために呼び出すことができ、最後にラッパーの「すべてのシーケンスを修正する」手順が表示されるまで待つだけです。

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;

その手順はそれ自体で便利ですが、それを呼び出し、シーケンス命名規則を使用してプログラムですべてを指定し、既存のテーブル/フィールドで使用される最大値を探す別の手順を追加しましょう...

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;

今はガスで調理中!

上記の手順は、テーブル内のフィールドの最大値をチェックし、テーブル/フィールドのペアからシーケンス名を構築し、その検出された最大値で「Reset_Sequence」を呼び出します。

このパズルの最後のピースとケーキのアイシングが次に来る...

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;

私の実際のデータベースでは、このメカニズムによってリセットされるシーケンスが他に約 100 あるため、上記の手順でReset_Sequence_to_Dataへの呼び出しがさらに 97 回あります。

大好きです?嫌い?無関心?

于 2011-05-19T17:35:59.060 に答える
10

次のスクリプトは、シーケンスを目的の値に設定します。

PCS_PROJ_KEY_SEQという名前の新しく作成されたシーケンスとテーブル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;
/
于 2010-11-04T18:53:27.913 に答える
6

このストアド プロシージャは、シーケンスを再開します。

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;

/

于 2009-07-29T17:23:58.290 に答える
5

Oracleでシーケンスをリセットする別の方法があります。それは、プロパティmaxvaluecycleプロパティを設定することです。シーケンスのnextvalがに当たるとmaxvaluecycleプロパティが設定されている場合minvalueは、シーケンスのから再開されます。

負の値を設定する場合と比較した場合のこの方法の利点はincrement by、リセットプロセスの実行中にシーケンスを引き続き使用できるため、リセットを実行するために何らかの形で停止する必要が生じる可能性が低くなることです。

の値maxvalueは現在の値よりも大きくする必要があるため、以下の手順には、手順での選択とプロパティの設定のnextval間にシーケンスに再度アクセスした場合にバッファを許可するオプションのパラメータが含まれています。nextvalcycle

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 

現状の手順では、別のセッションが値0をフェッチする可能性がありますが、これは問題になる場合と問題にならない場合があります。そうである場合は、いつでも次のことができます。

  • minvalue 1最初の変更で設定
  • nextval2番目のフェッチを除外します
  • ステートメントを移動して、nocycleプロパティを別のプロシージャに設定し、後日実行できるようにします(これを実行する場合)。
于 2013-02-10T17:09:03.527 に答える
4

1)次のようなシーケンスを作成するとします。

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

2)ここで、SEQUENCEから値をフェッチします。以下に示すように、4回フェッチしたとしましょう。

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

3)上記の4つのコマンドを実行すると、SEQUENCEの値は4になります。ここで、SEQUENCEの値を再び1にリセットしたとします。次の手順に従います。以下に示すのと同じ順序ですべての手順を実行します。

  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
于 2009-12-11T04:06:00.290 に答える
2

シーケンスによって返される次の値を変更するためのより堅牢な手順と、さらに多くの手順を次に示します。

  • まず、動的 SQL ステートメントを直接作成するために渡された文字列が使用されないため、SQL インジェクション攻撃から保護されます。
  • 次に、次のシーケンス値が最小または最大シーケンス値の範囲外に設定されるのを防ぎます。はnext_value!=ととmin_valueの間です。min_valuemax_value
  • 第 3 に、クリーンアップ時に現在の (または提案された)increment_by設定と他のすべてのシーケンス設定が考慮されます。
  • 最初のパラメーターを除く 4 番目のすべてのパラメーターはオプションであり、指定されていない限り、現在のシーケンス設定がデフォルトとして使用されます。オプションのパラメーターが指定されていない場合、アクションは実行されません。
  • 最後に、存在しない (または現在のユーザーが所有していない) シーケンスを変更しようとすると、ORA-01403: no data foundエラーが発生します。

コードは次のとおりです。

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;
于 2015-08-14T19:32:49.663 に答える
2

シーケンスの INCREMENT 値を変更し、インクリメントしてから元に戻す操作は非常に簡単です。さらに、シーケンスを削除/再作成した場合のように、すべての許可を再確立する必要がないという追加の利点があります。

于 2008-09-15T15:17:57.640 に答える
1

すべての自動インクリメント シーケンスを実際のデータと一致させる方法は次のとおりです。

  1. このスレッドで既に説明されているように、次の値を強制する手順を作成します。

    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. すべてのシーケンスを実際のコンテンツと照合する別の手順を作成します。

    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;
    

ノート:

  1. 手順はトリガー コードから名前を抽出し、命名規則に依存しません
  2. 実行前に生成されたコードを確認するには、最後の 2 行でコメントを切り替えます
于 2017-01-08T15:35:00.180 に答える
-1

私のために働いたストアドプロシージャ

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;

ストアド プロシージャの使用方法:

execute reset_sequence('company_sequence','company');
于 2019-11-18T22:03:48.357 に答える