預計閱讀時間:4分鐘微信
老婆昨兒提了一個問題,一張表中的字段,存儲的是用","分隔的字符串,是否能夠按照",",拆成多行?函數
舉個例子,TBL_ROW表,三個字段,其中POS字段,包含以","分隔的字符串,需求就是將POS中","分隔的字符串,連同NAME和NATIONALITY,拆成多行,spa
CREATE TABLE TBL_ROW
(
NAME VARCHAR2(10),
NATIONALITY VARCHAR2(10),
POS VARCHAR2(200)
);
INSERT INTO TBL_ROW VALUES('張稀哲','中國','前衛,前腰,前鋒');
INSERT INTO TBL_ROW VALUES('奧古斯托','巴西','後腰,前腰,前衛,前鋒');
INSERT INTO TBL_ROW VALUES('比埃拉','西班牙','前衛,前腰');
SELECT * FROM tbl_row;
NAME NATIONALITY POS
------- ----------- ----------------------
傲骨 巴西 後腰,前腰,前衛,前鋒
張稀哲 中國 前衛,前腰,前鋒
比埃拉 西班牙 前腰,前衛
第一種寫法:.net
使用正則函數,解析","分隔的字符,使用connect by層級查詢,distinct進行去重的操做,設計
select DISTINCT NAME, nationality,
regexp_substr(pos, '[^,]+',1,level)
FROM tbl_row
connect by level <= length(decode(substr(pos,-1),',',substr(pos,1,length(pos)-1),pos)) - length(REPLACE(pos,',',''))+1
ORDER BY NAME;
對應的執行計劃,code
第二種寫法:regexp
使用substr分隔字符串,使用connect by層級查詢,orm
SELECT NAME,nationality,substr(a.pos, instr(a.pos, ',', 1, levels.lvl) + 1, instr(a.pos, ',', 1, levels.lvl + 1) -(instr(a.pos, ',', 1, levels.lvl) + 1))
FROM
(SELECT NAME,',' || pos || ',' AS pos,nationality,length(pos) - nvl(length(REPLACE(pos, ',')), 0) + 1 AS cnt
FROM tbl_row) a,
(SELECT rownum AS lvl
FROM (SELECT MAX(length(pos || ',') - nvl(length(REPLACE(pos, ',')), 0)) max_len FROM tbl_row)
CONNECT BY LEVEL <= max_len) levels
WHERE levels.lvl <= a.cnt
ORDER BY NAME;
對應的執行計劃,blog
獲得的結果相同,ci
NAME NATIONALITY POS
------- ----------- -------
傲骨 巴西 前腰
傲骨 巴西 前衛
傲骨 巴西 前鋒
傲骨 巴西 後腰
張稀哲 中國 前鋒
張稀哲 中國 前腰
張稀哲 中國 前衛
比埃拉 西班牙 前衛
比埃拉 西班牙 前腰
總結一下,
1. 第二種寫法相比第一種寫法,略優一些,數據量小,區分不明顯。
2. POS字段的設計,很是不合理,從理論上講,不符合第三範式,不是原子拆分,所以纔可能有這種需求。
3. 經驗告訴咱們,老婆的問題,不能不重視,以最小的代價,先解決了再說。
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - bisal的我的雜貨鋪(gh_e8769c7350b1)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。