Oracle 8i 前大量使用 LONG/LONG RAW 儲存大型文本/二進制資料。遷移此類表時,CREATE TABLE AS SELECT (CTAS) 會報 ORA-00997: illegal use of LONG datatype。SQL*Plus 內建 COPY 命令雖屬舊功能(8.0 凍結、不支援 LOB/新型別),但對 LONG 遷移仍是最輕量、無需導出導入的單指令方案。
SQL> CREATE TABLE my_views AS SELECT * FROM user_views;
ERROR at line 2:
ORA-00997: illegal use of LONG datatype
-- user_views.TEXT 為 LONG 型別
COPY FROM TO
CREATE
USING ;
-- 參數說明
-- FROM/TO: 連接字串,省略時使用當前連接
-- CREATE/REPLACE/APPEND/INSERT: 目標表動作
-- USING: 查詢語句,支援 WHERE、JOIN
-- 1. 設定 LONG 顯示長度(避免截斷)
SET LONG 100000
SET LONGCHUNKSIZE 10000
SET ARRAYSIZE 50
SET COPYCOMMIT 0
-- 2. 執行 COPY
SQL> COPY FROM CREATE my_views USING SELECT * FROM user_views;
Array fetch/bind size is 50
Will commit when done. (copycommit is 0)
Maximum long size is 100000. (long is 100000)
Table MY_VIEWS created.
1 rows selected from DEFAULT HOST connection.
1 rows inserted into MY_VIEWS.
1 rows committed into MY_VIEWS at DEFAULT HOST connection.
-- 3. 驗證結構
SQL> DESC my_views;
Name Null? Type
---------------- -------- --------------------
VIEW_NAME NOT NULL VARCHAR2(30)
TEXT_LENGTH NUMBER(38)
TEXT LONG
TYPE_TEXT_LENGTH NUMBER(38)
TYPE_TEXT VARCHAR2(4000)
OID_TEXT_LENGTH NUMBER(38)
OID_TEXT VARCHAR2(4000)
VIEW_TYPE_OWNER VARCHAR2(30)
VIEW_TYPE VARCHAR2(30)
SUPERVIEW_NAME VARCHAR2(30)
| 支援 | 不支援 (8.0 後新增) |
|---|---|
| CHAR, VARCHAR2 | CLOB, NCLOB, BLOB, BFILE |
| NUMBER | XMLTYPE |
| DATE | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
| LONG, LONG RAW | INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND |
| RAW | 用戶定義型別 (Object, Collection, REF) |
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| COPY | 少量 LONG 表、臨時遷移 | 單指令、無需 Dump 檔、無額外工具 | 不支援新型別、單執行緒、無並行、8.0 凍結 |
| EXP/IMP | 全庫/多表、跨版本 | 支援所有型別、成熟穩定 | 客戶端工具、效能較慢、需檔案系統空間 |
| EXPDP/IMPDP | 10g+、大量資料、並行 | 服務端並行、壓縮/加密/過濾、可重啟 | 不支援 9i 前版本、需目錄物件 |
| CTAS + TO_LOB | 12c+、永久轉換 LONG→CLOB | 一次性轉型、後續支援所有 LOB 操作 | 需鎖表、產生 Undo/Redo、不可逆 |
-- 1. 新增 CLOB 欄位
ALTER TABLE my_views ADD (text_clob CLOB);
-- 2. 更新轉換(分批 Commit 避免 Undo 爆滿)
DECLARE
CURSOR c IS SELECT rowid, text FROM my_views WHERE text IS NOT NULL FOR UPDATE;
l_clob CLOB;
BEGIN
FOR r IN c LOOP
l_clob := TO_LOB(r.text);
UPDATE my_views SET text_clob = l_clob WHERE rowid = r.rowid;
IF MOD(c%ROWCOUNT, 100) = 0 THEN COMMIT; END IF;
END LOOP;
COMMIT;
END;
/
-- 3. 刪除舊 LONG 欄位、重命名
ALTER TABLE my_views DROP COLUMN text;
ALTER TABLE my_views RENAME COLUMN text_clob TO text;
COPY 是「搶險工具」,適合緊急遷移少量舊 LONG 表。長期治理應規劃 LONG → CLOB 全量轉型,徹底消除 ORA-00997 限制,獲得完整 LOB 功能與效能優化能力。