私はようやくMySQLからOracleへの移行に取り掛かり、SQLDeveloper移行ツールがどれほどうまく機能しているかにうれしく思いました。それは私のAUTOINCREMENTフィールドを取り、代わりに私のテーブルのシーケンスを作成しました。また、データの移行もうまくいきました。
私が見る唯一の本当のルーズエンドは、シーケンスを作成したときに、テーブル内の既存のデータを考慮せず、代わりにすべてのシーケンスがNEXTVAL 1を開始していることです。
主キー列のMAX値に基づいてシーケンスの次の値を設定する単純なPL/SQLスクリプト特定のテーブルのを特定のシーケンスに想像できますしかし、私はこれを100回以上実行する必要があり、まあ、そのための忍耐力がありません。
SYSTEMスキーマのメタデータを使用して、ユーザースペース全体のすべてのテーブル/シーケンスのペアに対して動的にこれを実行するPL/SQLスクリプトを記述できる方法があるのでしょうか。これを処理する方法を他にもっと良いアイデアがある人はいますか?ところで私はインターンを使い果たしました。
オンラインで動的に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;
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;