2

我们char(1)在 Oracle 中使用列来存储布尔值,其中的值是"1"or"0"代表真或假。但是,我想将这些更改为number(1)列,其中值为1or 0。如果表中已经存在值,您似乎无法更改此列的类型。所以我必须做这样的事情:

ALTER TABLE TPM_TRAININGPLANSOLUTIONS DROP CONSTRAINT SYS_C0010178;
ALTER TABLE TPM_TRAININGPLANSOLUTIONS RENAME COLUMN ISMARKERCOMPLETION TO ISMARKER_CHAR;
ALTER TABLE TPM_TRAININGPLANSOLUTIONS ADD (ISMARKERCOMPLETION NUMBER(1) NOT NULL);
UPDATE TPM_TRAININGPLANSOLUTIONS SET ISMARKERCOMPLETION = ISMARKER_CHAR; -- This takes about 10 min
ALTER TABLE TPM_TRAININGPLANSOLUTIONS DROP COLUMN ISMARKER_CHAR; -- Also very slow

ALTER TABLE TPMDBO.TPM_TRAININGPLANSOLUTIONS
    ADD ( CONSTRAINT SYS_C0010178
    CHECK (ISMARKERCOMPLETION in (0,1))
    NOT DEFERRABLE INITIALLY IMMEDIATE VALIDATE );

但是,我们的数据库中有几十个这样的列。有没有更快的方法来做到这一点?

4

2 回答 2

3

没有简单的方法来做你正在做的事情。您可以使用系统表为您生成 DDL,但您仍然需要知道列名。但是,有更简单的方法可以将其映射到一个数字,而无需更改任何内容。

首先,您需要确保您的列实际上是您分配的值。

ALTER TABLE TPMDBO.TPM_TRAININGPLANSOLUTIONS
    ADD ( CONSTRAINT chk_TPM_TRAININGPLANSOLUTIONS_IMC
    CHECK (ISMARKERCOMPLETION in ('0','1'))
    NOT DEFERRABLE INITIALLY IMMEDIATE VALIDATE );

然后,您可以在表上创建一个虚拟列

alter table tpm_trainingplansolutions add ( 
   ismarkercompletion_num generated always as (to_number(ismarkercompletion)) virtual
   );

或者表格顶部的视图,它将特定列转换为 NUMBER。

两者都可能会减少工作量,但现在您需要知道列名。做你正在做的事情并确保你的数据库是正确的。

顺便说一句,您正在使用前缀创建约束SYS_,请不要这样做......创建具有有意义名称的约束并且不要试图模仿 Oracle。

如果您想更改所有CHAR(1) 列,您可以使用USER_TAB_COLUMNS来识别具有此特征的列并使用它为您生成 DDL,例如

select 'ALTER TABLE '
        || table_name 
        || ' RENAME COLUMN '
        || column_name 
        || ' TO ' || substr(column_name, 1, length(column_name) - 5) 
        || '_CHAR ;'
  from user_tab_columns
 where data_type = 'CHAR'
   and data_length = 1

您可能还必须使用USER_CONS_COLUMNS ......

于 2013-05-10T20:43:50.987 回答
0

如果您有很多专栏,我认为您应该做的是

  1. 禁用基表的所有约束
  2. create as select具有所需列数据类型的基表中的新表
  3. 从基表复制约束
  4. 用新表替换基表

一次更改表一列可能会导致很多问题,例如碎片和链接。为了保持数据库健康,您将被迫以任何方式重建它。所以,你不妨从一开始就以正确的方式去做。

于 2013-05-11T05:36:42.403 回答