sql - 更改多个表的列长度

标签 sql database oracle orm ddl

因此,我们刚刚发现 Oracle DBMS 中的 254 个表中有一个名为 "Foo" 的列,其长度错误 - Number(10) 而不是 Number(3)

foo 列是表 PK 的一部分。
这些表还有其他带有 forigen 键的表。

我所做的是:

  1. 使用临时表备份该表。
  2. 禁用了表的外键。
  3. 禁用了与 foo 列的 PK。
  4. 将所有行的 foo 列清空。
  5. 已恢复上述所有内容

但现在我们发现这不仅仅是几张 table ,而是254张 table

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

附注我有 DBA 权限。

最佳答案

有一种更简单的方法来生成您想要的脚本,使用系统表 user_tablesuser_constraints动态生成DDL。缺点是这需要停机时间。另请注意,我使用 truncate命令而不是删除,后者应该更快。

假设一个简单的表格如下所示:

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列,这不会逐表完成,而是逐步完成,这样所有约束都会同时禁用,从而避免出现问题。如果您害怕(我会害怕),请从查询中删除 _backup 表的 drop ;这意味着无论发生什么问题,你都是安全的。

如果您在 SQL*Plus 中运行此命令,您还需要包含每当 sqlerror exit 时,这样如果出现问题(例如没有更多表空间),您就不会截断您尚未截断的内容没有备份。逐步运行它可能是值得的,这样您就知道一切都已正确完成。

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

关于sql - 更改多个表的列长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12278474/

相关文章:

mysql - 如何向mysql表添加动态数据

oracle - 如何对 >2 个表进行外连接 (Oracle)

database - 提供多版本数据库以向后兼容生产应用程序/数据库

java - 在 JSP 中动态建立 Oracle DB 连接

sql - 如何明智地按一组增加列

sql - 如何从雪花数据库中的Varchar "JSON Array"中选择元素?

ruby-on-rails - 服务器端数据库编程 : why?

mysql - 如果发生 MySQL/InnoDB 'lock wait timeout',锁在空闲时是否仍会被授予?

sql - 为什么数据库设计者不让 IDENTITY 列从最小值而不是 1 开始?

php - Wordpress 数据库不小心更改了 URL