更改多个表的列长度

时间:2012-09-05 09:36:56

标签: sql database oracle orm ddl

因此,我们发现我们Oracle DBMS中的254个表中有一列名为“Foo”,长度错误 - Number(10)而非{{1} }。

Number(3)列是表格PK的一部分 这些表有其他带有forigen键的表。

我做的是:

  1. 使用临时表备份表。
  2. 禁用表格的forigen键。
  3. 使用foo列禁用PK。
  4. 为所有行添加foo列。
  5. 恢复以上所有
  6. 但是现在我们发现它不只是几张桌子而是 254桌子

    是否有一种简单的方法,(或至少比这更容易)改变列的长度?

    P.S。我有DBA权限。

3 个答案:

答案 0 :(得分:3)

有一种更简单的方法来生成所需的脚本,使用系统表user_tablesuser_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

由于列stage,这将不是逐个表地进行,而是逐个进行,以便同时禁用所有约束,这将避免出现问题。如果你害怕(我会),那么从查询中删除drop_backup表;这意味着无论出了什么问题,你都是安全的。

如果你在SQL * Plus中运行它,你也想要包含whenever sqlerror exit,这样如果出现问题,例如没有更多的表空间,你就不会截断你没有备份的东西。它可能几乎值得一步一步地运行它,以便你知道一切都已正确完成。

我建议在具有几个表的不同用户上对此进行测试,以确保它能够完成您所需的一切。

答案 1 :(得分: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>;

对于所有表格。

答案 2 :(得分:0)

您的解决方案有效,但需要大量工作并且意味着停机时间。

由于物理上NUMBER(3)与具有更强约束的NUMBER(10)完全相同,因此您可以添加CHECK约束并获得相同的逻辑限制,而无需停机:

LOOP
   ALTER TABLE <table_name> ADD CONSTRAINT <table_foo_chk> CHECK (foo < 1000);
END LOOP;