web-dev-qa-db-ja.com

すべてのOracleシーケンスをターゲットテーブルPKのMAX値にリセットしますか?

私はようやくMySQLからOracleへの移行に取り掛かり、SQLDeveloper移行ツールがどれほどうまく機能しているかにうれしく思いました。それは私のAUTOINCREMENTフィールドを取り、代わりに私のテーブルのシーケンスを作成しました。また、データの移行もうまくいきました。

私が見る唯一の本当のルーズエンドは、シーケンスを作成したときに、テーブル内の既存のデータを考慮せず、代わりにすべてのシーケンスがNEXTVAL 1を開始していることです。

主キー列のMAX値に基づいてシーケンスの次の値を設定する単純なPL/SQLスクリプト特定のテーブルの特定のシーケンスに想像できますしかし、私はこれを100回以上実行する必要があり、まあ、そのための忍耐力がありません。

SYSTEMスキーマのメタデータを使用して、ユーザースペース全体のすべてのテーブル/シーケンスのペアに対して動的にこれを実行するPL/SQLスクリプトを記述できる方法があるのでしょうか。これを処理する方法を他にもっと良いアイデアがある人はいますか?ところで私はインターンを使い果たしました。

4
maple_shaft

オンラインで動的にallシーケンスを現在の最大IDに設定するスクリプトが見つからなかったため、このスクリプトを作成しました。 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;
2
Blama

PL/SQLを何年も離れていた後、ほとんどのシーケンスを修正する次の手順を実行することができました。このフックは、SYSTEMとしてログインしたときにSQL DeveloperのMySQLからOracleへの移行ツールを実行した後、SYSTEMユーザースペースに一連のメタデータテーブルを作成するようです。

MD_TABLES ... MD_SEQUENCESなど...

ツールはシーケンスを設定しませんでしたが、MD_SEQUENCESテーブルには、次のシーケンスでNEXTVALが返す必要のある列SEQ_STARTがすでに含まれていることがわかります。次の手順でこの情報を使用して、FFLユーザースペース内のすべてのテーブルに対してこの情報を使用しました。

set serveroutput on;
/

DECLARE
TYPE name_array is array(50) OF varchar2(100);
var_tables  name_array; 
var_seq_id number(20);

cursor c1 is
SELECT distinct table_name
  FROM system.md_tables;

cursor c2 is
SELECT distinct name, seq_start from system.md_sequences;

BEGIN

  FOR i IN c2
    LOOP
          select regexp_substr(i.name, '[^_]+', 1, level) as output bulk collect into var_tables
          from dual
          connect by level <= length(regexp_replace(i.name, '[^_]+')) + 1;
        BEGIN
         execute immediate 'select max(' || var_tables(2) || ') from ffl.' || var_tables(1) || ' ' into var_seq_id;
         dbms_output.put_line(var_seq_id);

          execute immediate
          'alter sequence ffl.' || i.name || ' increment by ' || var_seq_id || ' minvalue 0';

          execute immediate
          'select ffl.' || i.name || '.nextval from dual' INTO var_seq_id;

          execute immediate
          'alter sequence ffl.' || i.name || ' increment by 1 minvalue 0';

        EXCEPTION WHEN OTHERS THEN
         dbms_output.put_line('Exception at column id: ' || var_tables(2));
        END;
    END LOOP;
END;
1
maple_shaft