Oracle無內建SPLIT,常見三種實作路徑各有優劣。本文提供完整代碼、效能特性與選型建議。
CREATE OR REPLACE TYPE str_split AS TABLE OF VARCHAR2(4000);
/
CREATE OR REPLACE FUNCTION splitstr(p_string VARCHAR2, p_delimiter VARCHAR2)
RETURN str_split
AS
v_list str_split := str_split();
v_start NUMBER := 1;
v_pos NUMBER;
BEGIN
LOOP
v_pos := INSTR(p_string, p_delimiter, v_start);
IF v_pos = 0 THEN
v_list.EXTEND;
v_list(v_list.COUNT) := SUBSTR(p_string, v_start);
EXIT;
ELSE
v_list.EXTEND;
v_list(v_list.COUNT) := SUBSTR(p_string, v_start, v_pos-v_start);
v_start := v_pos + 1;
END IF;
END LOOP;
RETURN v_list;
END;
/
-- 使用:SELECT * FROM TABLE(splitstr('a,b,c', ','));
CREATE OR REPLACE TYPE str_split AS TABLE OF VARCHAR2(4000);
/
CREATE OR REPLACE FUNCTION splitstr_pipe(p_string VARCHAR2, p_delimiter VARCHAR2)
RETURN str_split PIPELINED
AS
v_len NUMBER := LENGTH(p_string);
v_start NUMBER := 1;
v_pos NUMBER;
BEGIN
WHILE v_start <= v_len LOOP
v_pos := INSTR(p_string, p_delimiter, v_start);
IF v_pos = 0 THEN
PIPE ROW(SUBSTR(p_string, v_start));
EXIT;
ELSE
PIPE ROW(SUBSTR(p_string, v_start, v_pos-v_start));
v_start := v_pos + 1;
END IF;
END LOOP;
RETURN;
END;
/
-- 使用:SELECT * FROM TABLE(splitstr_pipe('a,b,c', ','));
FETCH FIRST N ROWS提前終止PIPELINED關鍵字,10g+支援
SELECT DBMS_LOB.SUBSTR(
REGEXP_SUBSTR('abc,def,ggg,1,2,3,4,5', '[^,]+', 1, x.n)
) AS token
FROM DUAL,
(SELECT ROWNUM n FROM DUAL CONNECT BY ROWNUM <= 100) x
WHERE REGEXP_SUBSTR('abc,def,ggg,1,2,3,4,5', '[^,]+', 1, x.n) IS NOT NULL;
CONNECT BY遞歸有上限(預設100/最大MAX_RECURSION_DEPTH)、大量資料效能較差'[^,]+' 為「非逗號字元一或多個」;ROWNUM <= 100 限制最大分割段數| 場景 | 推薦方案 | 理由 |
|---|---|---|
| PL/SQL程式內部頻繁呼叫 | PIPELINED函數 | 效能最佳、記憶體可控、可並行 |
| 臨時SQL/報表/一次性分析 | REGEXP + CONNECT BY | 免部署、正則強大、可讀性高 |
| 舊版本(9i-) / 簡單邏輯 | 傳統集合函數 | 相容性最好 |
| 大量資料(>10萬段)分割 | PIPELINED + 並行 | 流式處理避免OOM |
JSON_TABLE:將JSON陣列轉關聯行XMLTABLE:XML路徑提取LISTAGG逆向操作(行轉字串)