2013-05-10 134 views
2

我們使用char(1)列來存儲Oracle中的布爾值,其值爲"1""0"以表示true或false。但是,我想將其更改爲number(1)列,其中值爲10。看起來如果表中已有值,則不能更改此列的類型。所以我必須這樣做:有沒有辦法在Oracle中將所有char(1)列更改爲number(1)列?

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); 

但是,我們在我們的數據庫中有很多這些列。有沒有更快的方法來做到這一點?

+1

出於好奇,你爲什麼要這麼做?原因? – shahkalpesh 2013-05-10 20:22:13

+0

@shahkalpesh - 好問題。 .NET Entity Framework將'number(1)'映射到布爾值,其中'char(1)'映射到一個String。 – 2013-05-10 20:24:17

+0

消息很明確,我認爲你正在做的是唯一的解決方案... – Sebas 2013-05-10 20:25:16

回答

3

有沒有簡單的方法來做你在做什麼;你可以使用系統表爲你生成DDL,但你仍然需要知道列名。但是,有更簡單的方法將其映射到一個數字,而不會更改任何內容。

首先,您需要確保您的列實際上是您分配的值。

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

然後,您可以在表上創建一個virtual column

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

或者在表的頂部視圖,casts特定列的數字。

要麼可能會導致少一點工作,但現在很多,因爲你需要知道列名。做你正在做的事情,並確保你的數據庫是正確的。

順便說一下,您正在創建一個前綴爲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,以及...

+0

是的,我不知道誰想出了這些約束名稱。它們在數據庫中的任何地方都可以使用,但我認爲它們最初是通過某種工具創建的。對於我們所有的外鍵,我們也使用'TABLEFOO_FK1','TABLEFOO_FK2','TABLEFOO_FK3'。嘆。 – 2013-05-10 20:47:11

+0

它看起來像Oracle的默認@Mike,如果你在DDL中創建自己,可能會很危險。這意味着人們在表DDL中創建了約束,但沒有命名它們...... – Ben 2013-05-10 20:50:08

+0

我想我可以將所有約束和FK名稱重新命名爲描述性的*到我的待辦事項列表。謝謝你的回答,但是,這有助於很多! – 2013-05-10 20:53:26

0

如果你有很多列,我認爲你應該做的是

  1. 禁用基地所有約束表
  2. create as select從基表中獲得所需列數據類型的新表
  3. 從基表複製約束
  4. 新表

同時改變表一列替換基表會造成大量的像碎片和鏈接的問題。爲了保持數據庫的健康,你將會以任何方式強制重建數據庫。所以,你不妨從一開始就以正確的方式來做。

+0

CTAS意味着停止數據庫的_all_工作,儘管...您不能冒任何在基表上執行的DML的風險。 .. – Ben 2013-05-11 08:50:52

+0

和更改列意味着鎖定整個表。 – haki 2013-05-11 09:41:09

相關問題