Sql 更改多个表的列长度
因此,我们刚刚发现Oracle DBMS中的254个表有一个名为Foo的列,其长度错误-Number10而不是Number3 该foo列是表PK的一部分。 这些表还有其他表,其中有forigen键 我所做的是: 使用临时表备份表。 已禁用表的forigen键。 使用foo列禁用PK。 为所有行的foo列设置为空。 恢复了以上所有内容 但现在我们发现不仅仅是几张桌子,而是254张桌子 有没有一种简单的方法,或者至少比这更简单的方法来改变列的长度 另外,我有DBA权限。我们所做的是:Sql 更改多个表的列长度,sql,database,oracle,orm,ddl,Sql,Database,Oracle,Orm,Ddl,因此,我们刚刚发现Oracle DBMS中的254个表有一个名为Foo的列,其长度错误-Number10而不是Number3 该foo列是表PK的一部分。 这些表还有其他表,其中有forigen键 我所做的是: 使用临时表备份表。 已禁用表的forigen键。 使用foo列禁用PK。 为所有行的foo列设置为空。 恢复了以上所有内容 但现在我们发现不仅仅是几张桌子,而是254张桌子 有没有一种简单的方法,或者至少比这更简单的方法来改变列的长度 另外,我有DBA权限。我们所做的是: CREATE
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>;
对于所有表格。我们所做的是:
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>;
对于所有的表。您的解决方案是可行的,但工作量很大,并且意味着停机 由于数字3在物理上与数字10完全相同,具有更强的约束,因此您可以添加检查约束,并在不停机的情况下获得相同的逻辑约束:
LOOP
ALTER TABLE <table_name> ADD CONSTRAINT <table_foo_chk> CHECK (foo < 1000);
END LOOP;
您的解决方案可以工作,但工作量很大,并且意味着停机 由于数字3在物理上与数字10完全相同,具有更强的约束,因此您可以添加检查约束,并在不停机的情况下获得相同的逻辑约束:
LOOP
ALTER TABLE <table_name> ADD CONSTRAINT <table_foo_chk> CHECK (foo < 1000);
END LOOP;
有一种更简单的方法可以生成所需的脚本、使用系统表和动态生成DDL。缺点是这需要停机时间。还要注意,我使用的是命令而不是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
由于列阶段的原因,这将不是一个表一个表地完成,而是一个阶段一个阶段地完成,以便同时禁用所有约束,从而避免出现问题。如果你害怕,那么就从查询中删除掉_备份表;这意味着无论发生什么问题,你都是安全的
如果您在SQL*中运行此功能,并且还希望在sqlerror退出时包含它,以便在出现问题(例如没有更多表空间)时,不会截断未备份的内容。它可能几乎值得一步一步地运行,这样您就知道一切都已正确完成
我建议在不同的用户上使用几个表来测试它,以确保它可以完成您需要的所有操作。有一种更简单的方法来生成您想要的脚本,使用系统表并动态生成DDL。缺点是这需要停机时间。还要注意,我使用的是命令而不是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
由于列阶段的原因,这将不是一个表一个表地完成,而是一个阶段一个阶段地完成,以便同时禁用所有约束,从而避免出现问题。如果你害怕,那么就从查询中删除掉_备份表;这意味着无论发生什么问题,你都是安全的
如果您在SQL*中运行此功能,并且还希望在sqlerror退出时包含它,以便在出现问题(例如没有更多表空间)时,不会截断未备份的内容。它可能几乎值得一步一步地运行,这样您就知道一切都已正确完成
我建议用几个表在不同的用户上进行测试,以确保它能满足您的所有需要。没有级联删除,例如不需要的行为?乍一看似乎很危险,但我可能会错过一些东西。@RaphaëlAlthaus。哦,是的,我必须禁用引用表中的所有外键。我很快会在答案中添加这一点。{是我错过了一些东西…;}没有级联删除,例如不想要的行为?乍一看似乎很危险,但我可能会错过一些东西。@RaphaëlAlthaus。哦,是的,我必须禁用引用表中的所有外键。我很快会在答案中添加这一点。{是我漏掉了一些东西…;}这样做的缺点是,所有的插入和更新都必须永远根据该约束进行检查。@ben:与生成重做/撤消、从缓存中获取块等的大量工作相比,单次检查约束产生了无法检测到的开销。。。由更新/插入暗示。这对我没有帮助,因为我将它们设为3号,因为我们开始使用实体框架,它将一些映射为short,一些映射为int。无论如何,谢谢。这样做的缺点是,所有插入和更新都必须永远根据该约束进行检查。@ben:单一检查约束会产生一个与生成重做/撤消、从缓存获取块等的大量工作相比,无法检测到的开销量。。。这对我没有帮助,因为我们开始使用实体框架,所以我把它们设为3号
d它将一些映射为短,一些映射为int。无论如何,谢谢。谢谢!你能给上面看起来不好看的代码添加注释吗。我不想运行我不完全理解的DDL查询。我已经尝试让它更容易理解。。。并补充了一些警告:谢谢,我真的很感谢你的帮助和努力。最后一件事,chr10在做什么?我从来没有在查询中看到过这样的事情。没问题,我经常做类似的事情!这只是一个换行码ASCII 10,chr编码。这意味着在打印结果时,为了避免联合加载而连接在一起的语句位于不同的行上。谢谢!你能给上面看起来不好看的代码添加注释吗。我不想运行我不完全理解的DDL查询。我已经尝试让它更容易理解。。。并补充了一些警告:谢谢,我真的很感谢你的帮助和努力。最后一件事,chr10在做什么?我从来没有在查询中看到过这样的事情。没问题,我经常做类似的事情!这只是一个换行码ASCII 10,chr编码。这意味着在打印结果时,为了避免联合加载而连接在一起的语句位于不同的行上。