2

Oracleそのため、 DBMSの 254 個のテーブルに、 「Foo」Number(10)という名前の列が 1 つあり、長さが ではなく間違っていることがわかりましたNumber(3)

そのfoo列は、テーブルの PK の一部です。
これらのテーブルには、forigen キーを持つ他のテーブルがあります。

私がしたことは次のとおりです。

  1. 一時テーブルでテーブルをバックアップしました。
  2. テーブルへの forigen キーを無効にしました。
  3. foo列で PK を無効にしました。
  4. fooすべての行の列をnull にしました。
  5. 上記のすべてを復元しました

しかし今では、それが 2 つのテーブルではなく、254 個のテーブルであることがわかりました。

列の長さを変更する簡単な方法 (または少なくともこれよりも簡単) はありますか?

PS私はDBA権限を持っています。

4

3 に答える 3

3

必要なスクリプトを生成し、システム テーブルuser_tablesを使用してuser_constraints、DDL を動的に生成する簡単な方法があります。欠点は、これにはダウンタイムが必要なことです。また、より高速なtruncateコマンドではなくコマンドを使用していることにも注意してください。delete

次のような単純なテーブルを想定します。

create table a ( 
   foo number(10)
 , bar number(10)
 , constraint pk_a primary key (foo)
 , constraint fk_a foreign key ( bar ) references a(foo )
  );

この見栄えの悪いクエリ

select cmd
  from ( 
select table_name
     , 1 as stage -- Just used to order by at the end.
     , 'create table ' || table_name || '_backup as select * from ' 
                      || table_name || ';' || chr(10) as cmd
       -- chr(10) is LF
  from user_tab_columns -- View of all columns
 where column_name = 'FOO'
   and data_precision = 10 -- Length of the number
 union all
select table_name
     , 3 as stage
     ,  'truncate table ' || table_name || ';' || chr(10) -- Remove all data
       || 'alter table ' || table_name 
               || ' modify ( foo number(3));' || chr(10)
       || 'insert into ' || table_name || ' select * from ' 
            || table_name || '_backup;' || chr(10)
       || 'drop table ' || table_name || '_backup;' as cmd
  from user_tab_columns
 where column_name = 'FOO'
   and data_precision = 10
 union all
select ut.table_name
     , 2 as stage
       -- Disable the constraint
     , 'alter table ' || uc.table_name || ' disable constraint ' 
            || uc.constraint_name || ';' || chr(10) as cmd
  from user_constraints uc -- All named constraints
  join user_tab_columns ut
    on uc.table_name = ut.table_name
 where ut.column_name = 'FOO'
   and ut.data_precision = 10 
   and constraint_type = 'R' -- Foreign Key constraints (see link)
 union all
select ut.table_name
     , 4 as stage
     , 'alter table ' || uc.table_name || ' enable constraint ' 
          || uc.constraint_name || ';' || chr(10) as cmd
  from user_constraints uc
  join user_tab_columns ut
    on uc.table_name = ut.table_name
 where ut.column_name = 'FOO'
   and ut.data_precision = 10
   and constraint_type = 'R'
       )
 order by stage

以下を生成します。

create table A_backup as select * from A; -- Create your backup
alter table A disable constraint FK_A; -- Disable FKs
truncate table A; -- Remove all data in the table
alter table A modify ( foo number(3)); -- Reduce the size of the column
insert into A select * from A_backup; -- Replace all the data
drop table A_backup; -- Drop the backup
alter table A enable constraint FK_A; -- Re-enable FKs

column によりstage、これはテーブルごとではなくステージごとに行われるため、すべての制約が同時に無効になり、問題が回避されます。あなたが怖がっているなら(私はそう思うでしょう)、クエリからテーブルを削除しdropてください。_backupこれは、何がうまくいかなくても安全であることを意味します。

これを SQL*Plus で実行してwhenever sqlerror exitいる場合は、表領域がなくなったなどの問題が発生した場合に、バックアップしていないものを切り捨てないようにするためにも含める必要があります。すべてが正しく完了したことを確認できるように、段階的に実行する価値があるかもしれません。

いくつかのテーブルを使用して別のユーザーでこれをテストし、必要なすべてが実行されることを確認することをお勧めします。

于 2012-09-05T12:02:11.083 に答える
1

私たちが行ったことは次のとおりです。

CREATE TABLE <table_name_backup> as SELECT *  <table_name>;
DELETE <table_name>;    
ALTER TABLE <table_name> MODIFY (Foo NUMBER(3));
INSERT INTO <table_name> SELECT * FROM <table_name_backup>;
DROP <table_name_backup>;

すべてのテーブル。

于 2012-09-05T10:20:43.940 に答える
0

あなたのソリューションは機能しますが、多くの作業であり、ダウンタイムを意味します。

物理的にaは、より強力な制約を持つaNUMBER(3)とまったく同じNUMBER(10)であるため、制約を追加CHECKして、ダウンタイムなしで同じ論理制限を取得できます。

LOOP
   ALTER TABLE <table_name> ADD CONSTRAINT <table_foo_chk> CHECK (foo < 1000);
END LOOP;
于 2012-09-05T11:55:48.460 に答える