22:25:31 SQL> select * from t;
A
----------
10
22:25:32 SQL> desc t
名稱 是否為空? 類型
-------------------- --------- --------------------
A VARCHAR2(10)
22:25:34 SQL> alter table t modify(a number);
alter table t modify(a number)
*
第 1 行出現錯誤:
ORA-01439: 要更改數據類型, 則要修改的列必須為空
其實,類似的現象確實很多,如本來應該為date類型,結果被定義成varchar2類型等等,主要就是那些兼容的數據類型之間的轉換定義。當然,為什么一開始會犯這樣的錯誤,那可能原因就有多方面了,如一開始需求就不對等等。
下面,以上面那個例子為基礎,介紹兩種處理這種問題的方法。
第一種方法,通過增加列來完成
22:25:44 SQL> alter table t add (b number);
表已更改。
22:34:16 SQL> update t set b = to_number(a)
已更新 1 行。
22:34:39 SQL> update t set a = null;
已更新 1 行。
22:34:50 SQL> commit;
提交完成。
22:34:52 SQL> select * from t;
A B
---------- ----------
10
22:34:55 SQL> alter table t modify a number
表已更改。
22:35:21 SQL> update t set a=b;
已更新 1 行。
已用時間: 00: 00: 00.01
22:35:33 SQL> commit;
提交完成。
22:35:52 SQL> alter table t drop column b;
表已更改。
在這種方法中最后也可以先drop column a,然后rename column b to a,達到的效果是一樣的。
第二種方法:通過新建表,在新表上更改字段,最后rename新表來完成
22:41:44 SQL> create table t1 as select * from t where 1=2;
表已創建。
22:42:14 SQL> alter table t1 modify (a number);
表已更改。
22:42:24 SQL> insert into t1 select * from t;
已創建 1 行。
22:42:37 SQL> commit;
提交完成。
22:42:40 SQL> drop table t;
表已刪除。
22:42:46 SQL> rename t1 to t;
表已重命名。
22:43:00 SQL> desc t;
名稱 是否為空? 類型
-------------- --------- -------------
A NUMBER
我就知道這兩種常見的方法,不知道還有沒有什么其他的好方法。如果有,請分享。建議使用第一種。
約束和索引都被摧殘了,可以做個實驗證明一下。
先建立測試表并插入數據
15:28:45 SQL> create table t (a varchar2(10) not null);
表已創建。
已用時間: 00: 00: 00.03
15:28:47 SQL> insert into t values ('10');
已創建 1 行。
已用時間: 00: 00: 00.00
15:28:55 SQL> commit;
提交完成。
已用時間: 00: 00: 00.00
然后增加一個列,并且把數據復制過去
15:29:08 SQL> alter table t add (b number);
表已更改。
已用時間: 00: 00: 00.01
15:29:31 SQL> update t set b=to_number(a);
已更新 1 行。
已用時間: 00: 00: 00.01
15:29:42 SQL> commit;
提交完成。
已用時間: 00: 00: 00.00
15:29:45 SQL> alter table t modify b not null;
表已更改。
已用時間: 00: 00: 00.10
在原來的列上建立索引和約束
15:29:59 SQL> create index ind_t_a on t(a);
索引已創建。
已用時間: 00: 00: 00.15
15:31:01 SQL> alter table t add constraint uk_t_a unique(a);
表已更改。
已用時間: 00: 00: 00.03
斗轉星移:
15:31:20 SQL> alter table t drop column a;
表已更改。
已用時間: 00: 00: 01.20
15:32:06 SQL> alter table t rename column b to a;
表已更改。
已用時間: 00: 00: 00.03
查看索引是否還在?可以看到索引已經被損壞了:
15:33:17 SQL> select index_name,status from user_indexes where table_name='T';
未選定行
已用時間: 00: 00: 00.12
15:34:20 SQL> select index_name,status from user_indexes order by 1;
INDEX_NAME STATUS
------------------------------ --------
PK_DEPT VALID
PK_EMP VALID
已用時間: 00: 00: 00.35
然后查看約束是否還在?可以看到它也被摧殘了
15:38:07 SQL> select constraint_name,constraint_type,invalid,table_name from user_constraints where table_name='T';
CONSTRAINT_NAME CONSTRAINT_TYPE INVALID TABLE_NAME
------------------------------ -------------------- ------- -----------
SYS_C005423 C T
已用時間: 00: 00: 00.03
15:38:24 SQL> select constraint_name,constraint_type,invalid,table_name from user_constraints;
CONSTRAINT_NAME CONSTRAINT_TYPE INVALID TABLE_NAME
------------------------------ -------------------- ------- ------------
BIN$lNdA2W97SK69TBAu945o7w==$0 C BIN$W9ZnSgtTS9+Fs/438TqKuA==$0
BIN$6JXde6KdTsum1GYM3py1eg==$0 C BIN$W9ZnSgtTS9+Fs/438TqKuA==$0
SYS_C005423 C T
FK_DEPTNO R EMP
PK_DEPT P DEPT
PK_EMP P EMP
已選擇6行。
已用時間: 00: 00: 00.23
驗證后,唯一約束已經不起作用了
15:38:31 SQL> select * from t;
A
----------
10
已用時間: 00: 00: 00.03
15:39:26 SQL> desc t;
名稱 是否為空? 類型
--------------- --------- ---------------------------
A NOT NULL NUMBER
15:39:29 SQL> insert into t values(10);
已創建 1 行。
已用時間: 00: 00: 00.01
15:39:38 SQL> commit;
提交完成。
已用時間: 00: 00: 00.00
15:39:44 SQL> select * from t;
A
----------
10
10
可能大家會問,為什么還有一個C約束呢?上面的查詢顯示它是not null約束:
15:51:06 SQL> select table_name,constraint_name,column_name from user_cons_columns where table_name='T';
TABLE_NAME CONSTRAINT_NAME COLUMN_NAME
------------------------------ ------------------------------ -----------------
T SYS_C005423 A
16:09:29 SQL> select search_condition from user_constraints where table_name='T';
SEARCH_CONDITION
--------------------------------------------------------------------------------
"A" IS NOT NULL
新聞熱點
疑難解答