6

あるDBから別のDBにデータを移行するためのスクリプトを作成しようとしています。現在私ができないことの1つは、シーケンスのnextvalを別のDBのシーケンスのnextvalに設定することです。

user_sequencesから値の違いを取得し、次の動的SQLステートメントを生成しました。

execute immediate 'alter sequence myseq increment by 100';
execute immediate 'select myseq.nextval from dual';
execute immediate 'alter sequence myseq increment by 1';

commit;

しかし、何も起こりません。私は何が欠けていますか?プロシージャの外で同じステートメントを実行すると、正常に機能します。

alter sequence myseq increment by 100;
select myseq.nextval from dual;
alter sequence myseq increment by 1;

commit;

編集:明確ではないことをすべての人に謝罪します。私は実際に同じDBのシーケンスを変更しています。リモートDBから設定する値のみを取得しています。おそらく、リモートDBは物事に影響を与えないため、言及する必要はありませんでした。私は自分の目標が何であるかを説明するためにそれについて言及しただけです。

ステップ1.リモートDBからシーケンスのnextvalを取得します。

select (select last_number
        from dba_sequences@remoteDB
        where upper(sequence_name) = upper(v_sequence_name)) - (select last_number
                                                                from user_sequences
                                                                where upper(sequence_name) = upper(v_sequence_name)) increment_by
from dual;    

手順2.次の値を使用して動的SQLステートメントを生成します。

execute immediate 'alter sequence myseq increment by 100';
execute immediate 'select myseq.nextval from dual';
execute immediate 'alter sequence myseq increment by 1';

commit;

エラーは発生しませんでしたが、何も起こりませんでした。DBMS_OUTPUT.PUT_LINEを使用してSQLステートメントを記述し、それらを外部で実行すると、機能しました。

4

4 に答える 4

7

シーケンスを新しい(より高い)値に動的に設定するコードを次に示します。私はこれを書いたので、スキーマ内のどのシーケンスでも機能します。

create or replace procedure resync_seq
    (p_seq_name in user_sequences.sequence_name%type)
is
    local_val pls_integer;
    remote_val pls_integer;
    diff pls_integer;
begin
    execute immediate 'select '|| p_seq_name ||'.nextval from dual'
           into local_val;
    select last_number into remote_val
    from user_sequences@remote_db
    where sequence_name = p_seq_name ;
    diff := remote_val - local_val;

    if diff > 0
    then
        execute immediate 'alter sequence  '|| p_seq_name ||' increment by ' ||to_char(diff);
        execute immediate 'select '|| p_seq_name ||'.nextval from dual'
           into local_val;
        execute immediate 'alter sequence  '|| p_seq_name ||' increment by 1';
    end if;

end;

DDLステートメントは暗黙的なコミット(実際には2つ)を発行するため、プロシージャはCOMMITを必要としません。

これを実行して、同期された値を次のように確認できます(SQL * PLusの場合)。

exec resync_seq('MYSEQ')
select myseq.currval
from dual

ちなみに、シーケンスを(元の開始値または別の低い値に)リセットする唯一の方法は、シーケンスを削除して再作成することです。


18cで、OracleはALTERSEQUENCEにRESTART機能を追加しました。簡単なオプション...

alter sequence myseq restart;

...シーケンスを元のCREATESEQUENCEステートメントのSTARTWITH句で指定された値にリセットします。もう1つのオプションでは、新しい開始点を指定できます。

alter sequence myseq restart start with 23000;

わくわくすることに、この新しい開始点は、現在の値よりも前または後ろにある可能性があります(シーケンスの通常の範囲内)。

1つの問題は、この新機能が文書化されていないことです(Oracleの内部使用のみ)。したがって、この機能を使用することは想定されていません。20cでも当てはまります。シーケンスの値を変更するために承認された唯一のメカニズムは、上記で概説したものです。

于 2012-04-30T14:45:47.903 に答える
3

私はあなたが何を意味するのか完全には理解できませんでしたが、ここに野生の推測があります:

コードには表示されませんが、別のデータベースでDDL(など)を実行することについて話しているCREATEのでALTER、データベースリンクを使用していると思います。データベースリンクを使用して、別のデータベースでDDLを実行することはできません。あなたはそれを考慮したいかもしれません。


あなたが提供した情報の後、これはあなたが必要とするものかもしれません。また、シーケンスの現在の値を設定する場合は、このドキュメントによると、ドロップ/作成する必要はありません。

declare
  ln_lastNumber DBA_SEQUENCES.LAST_NUMBER%type;
  lv_sequenceName DBA_SEQUENCES.SEQUENCE_NAME%type := 'MYSEQ';
begin
  select LAST_NUMBER
  into ln_lastNumber
  from DBA_SEQUENCES--or @remote_db;
  where
    --Your predicates;

  execute immediate 'drop sequence ' || lv_sequenceName;
  execute immediate 'create sequence ' || lv_sequenceName || ' starts with ' || ln_lastNumber;
exception
  when no_data_found then
    dbms_output.put_line('No sequence found!'); -- Or log somehow.
    raise;
  when others then
    raise;
end;
于 2012-04-30T11:53:26.437 に答える
0

また、動的SQLパッケージのDDLには、

AUTHID CURRENT_USER

パッケージ仕様を宣言するとき、現在のユーザーの資格情報をパッケージに持たせたい場合

于 2012-04-30T19:09:51.027 に答える
0

APCから提供されたコードを使用して、次のように変更しました。

create or replace procedure resync_seq
    (p_seq_name in user_sequences.sequence_name%type, 
     p_table_name in user_tables.table_name%type, 
     p_pk in user_cons_columns.column_name%type)
is
     local_val pls_integer;
     remote_val pls_integer;
     diff pls_integer;
begin
      execute immediate 'select '|| p_seq_name ||'.nextval from dual'
       into local_val;

       execute immediate 'select max('||p_pk||') from '||p_table_name ||' ' 
       into remote_val ;

       diff := remote_val - local_val;

       if diff > 0
          then
          execute immediate 'alter sequence  '|| p_seq_name ||' increment by ' ||to_char(diff);
          execute immediate 'select '|| p_seq_name ||'.nextval from dual'
       into local_val;
          execute immediate 'alter sequence  '|| p_seq_name ||' increment by 1';
       end if;

 end;
于 2015-10-08T17:34:39.790 に答える