將單一欄位內的逗號分隔值(如 '1,2,3')拆分為多列,是 ETL、報表、權限解析常見需求。本文提供純 SQL 解法,利用 CONNECT BY LEVEL 產生序列、INSTR/SUBSTR 切分字串,無需 PL/SQL 迴圈,效能優於 XMLTABLE 或 遞迴 CTE。
WITH src AS (
SELECT 'aaa' AS col_a, 'bbb' AS col_b, '1,2,3' AS col_c FROM dual
-- 實際使用時替換為:SELECT col_a, col_b, col_c FROM your_table
),
norm AS (
SELECT col_a, col_b,
',' || col_c || ',' AS c_str, -- 前後加逗號統一邊界
LENGTH(col_c || ',') - LENGTH(REPLACE(col_c, ',', '')) AS cnt -- 逗號數 = 元素數-1
FROM src
)
SELECT col_a, col_b,
SUBSTR(c_str,
INSTR(c_str, ',', 1, lvl) + 1,
INSTR(c_str, ',', 1, lvl + 1) - INSTR(c_str, ',', 1, lvl) - 1) AS col_c_split
FROM norm,
(SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL <= 100) gen -- 100 為單欄位最大拆分數,視需求調整
WHERE lvl <= cnt + 1; -- 元素數 = 逗號數 + 1
COL_A COL_B COL_C_SPLIT
----- ----- -----------
aaa bbb 1
aaa bbb 2
aaa bbb 3
',' || col_c || ',' 使首尾元素同樣被逗號包裹,INSTR 邏輯統一LENGTH(col_c || ',') - LENGTH(REPLACE(col_c, ',')) 等於逗號出現次數,元素數 = 逗號數 + 1dual 產生 1..N 序列,N 設為業務上限(如 100、1000)WITH src AS (
SELECT 'a' AS id, ' 1 , 2 , , 3 ' AS val FROM dual
),
norm AS (
SELECT id,
',' || TRIM(val) || ',' AS c_str,
REGEXP_COUNT(TRIM(val), ',') + 1 AS cnt
FROM src
)
SELECT id,
TRIM(SUBSTR(c_str,
INSTR(c_str, ',', 1, lvl) + 1,
INSTR(c_str, ',', 1, lvl + 1) - INSTR(c_str, ',', 1, lvl) - 1)) AS val_split
FROM norm,
(SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL <= 100)
WHERE lvl <= cnt
AND TRIM(SUBSTR(c_str,
INSTR(c_str, ',', 1, lvl) + 1,
INSTR(c_str, ',', 1, lvl + 1) - INSTR(c_str, ',', 1, lvl) - 1)) IS NOT NULL;
| 方法 | 語法 | 優點 | 缺點 |
|---|---|---|---|
| JSON_TABLE | SELECT jt.* FROM t, JSON_TABLE('["'||REPLACE(val,',','","')||'"]', '$[*]' COLUMNS val VARCHAR2(100) PATH '$') jt | 語意清晰、自動處理引號轉義 | 需 12.1.0.2+、字串需合法 JSON |
| XMLTABLE | SELECT xt.* FROM t, XMLTABLE(('"'||REPLACE(val,',','","')||'"')) xt | 11g+ 可用 | 效能較差、特殊字元需轉義 |
| 遞迴 CTE | WITH r(id, val, rest) AS (SELECT id, SUBSTR(val,1,INSTR(val,',')-1), SUBSTR(val,INSTR(val,',')+1) FROM t UNION ALL SELECT id, SUBSTR(rest,1,INSTR(rest,',')-1), SUBSTR(rest,INSTR(rest,',')+1) FROM r WHERE rest IS NOT NULL) SELECT id, val FROM r | ANSI 標準、可移植 | Oracle 11g+、效能略低於 CONNECT BY |
| 本文 INSTR/SUBSTR | 見上方核心 SQL | **效能最佳、10g+ 全支援、無特殊字元限制** | 語法較繁瑣 |
PIPELINED FUNCTION 封裝邏輯,搭配 PARALLEL_ENABLE 並行處理字串拆分看似瑣碎,實則考驗 SQL 基礎功力。掌握
INSTR/SUBSTR/CONNECT BY組合拳,應對 90% 拆分場景綽綽有餘。