把字串 '1,2,3,4,5',以逗號分隔,輸出為行,也就是 1
2345
隨手寫了乙個, oracle 10g 以上
有表如下
sql>select
* from
t; id name
---------- ----------------
1 0,1,5,2,8,10
2 9,7,8
withvmaxnum
as(
select
rownum ele
from
dual
connect
byrownum<=(
select
max(length(
name
)-length(
replace
(name
,','
,null
)))+1
from
t))
select
id,
decode(pos,0,substr(name
,lagpos+1),substr(
name
,lagpos+1,pos-lagpos-1))
name
from
(select
id,name
,ele,pos,nvl(lag(pos) over (partition
byid
order
byele),0) lagpos
from
(select
id,name
,ele,
instr(name
,','
,1,ele) pos
from
(select
/*+ all_rows no_merge(v2) use_merge(t,v2) */
t.id,t.name
,v2.ele
from
t,vmaxnum v2
where
ele<=length(
name
)-length(
replace
(name
,','
,null
))+1)))
order
byid,ele;
12 rows selected.
然後客戶那反饋說資料庫說9i的,報錯說connect by不能使用子查詢。
於是再稍做修改,在確定逗號不會超過99個的前提下,直接寫個常量100,可以支援9i
withvmaxnum
as(
select
rownum ele
from
dual
connect
byrownum<=100)
select
id,
decode(pos,0,substr(name
,lagpos+1),substr(
name
,lagpos+1,pos-lagpos-1))
name
from
(select
id,name
,ele,pos,nvl(lag(pos) over (partition
byid
order
byele),0) lagpos
from
(select
id,name
,ele,
instr(name
,','
,1,ele) pos
from
(select
/*+ all_rows no_merge(v2) use_merge(t,v2) */
t.*,v2.ele
from
t,vmaxnum v2
where
ele<=length(
name
)-length(
replace
(name
,','
,null
))+1)))
order
byid,ele;
後來想想這樣也不好,於是建議建立一張特定的iot表,儲存10000個數字,一般夠用了。
建立一張iot,共10000行,同樣支援9i
create table tnumber(ele,constraint pk_tnumber primary key(ele)) organization index asselect rownum id from dual connect by rownum<
=10000;
然後不再需要常量100,即保證準確,又保證較好的效能
create table t500 nologging aswith vmaxnum as (
select ele
from tnumber
where ele<
=(select max(length(name)-length(replace(name,',',null)))+1 from t))
select id,
decode(pos,0,substr(name,lagpos+1),substr(name,lagpos+1,pos-lagpos-1)) name
from (select id,name,ele,pos,nvl(lag(pos) over (partition by id order by ele),0) lagpos
from (select id,name,ele,
instr(name,',',1,ele) pos
from (select /*+ all_rows no_merge(v2) use_merge(t,v2) */
t.id,t.name,v2.ele
from t,vmaxnum v2
where ele<
=length(name)-length(replace(name,',',null))+1)))
order by id,ele;
12 rows selected.
下面測試一下效能:轉換50萬行試試,測試環境:dell d630 用了4年半的舊筆記本,磁碟都是碎片
sql> insert into t select rownum+4,'1,2,3,4' from dual connect by rownum<=500000;
500000 rows created.
sql> commit;
commit complete.
set timi on
sql> set timi on
sql> create table t500 nologging as
with vmaxnum as (
select ele
from tnumber
where ele<=(select max(length(name)-length(replace(name,',',null)))+1 from t))
select id,
decode(pos,0,substr(name,lagpos+1),substr(name,lagpos+1,pos-lagpos-1)) name
from (select id,name,ele,pos,nvl(lag(pos) over (partition by id order by ele),0) lagpos
from (select id,name,ele,
instr(name,',',1,ele) pos
from (select /*+ all_rows no_merge(v2) use_merge(t,v2) */
t.id,t.name,v2.ele
from t,vmaxnum v2
where ele<=length(name)-length(replace(name,',',null))+1)))
order by id,ele;
table created.
elapsed: 00:00:16.48
耗時16秒,含建表的寫盤時間
sql> select count(*) from t500;
count(*)
----------
2000012
當然還有別的寫法,比如簡單的可以這樣
select id,substr(name,instr(name,',',1,rownum)+1,instr(name,',',1,rownum+1)-instr(name,',',1,rownum)-1) namefrom (select id,','||name||',' name from t)
connect by rownum<
length
(translate(name,','||name,','));
或者10g以上用正規表示式也可以實現
這個方法可能不是最高效的,但也還可以。
這個sql的效能和字串含有的逗號的個數有關,逗號越多,也就是分隔項越多,效能越差。
oracle9i匯出oracle 10g的大字段
oracle9i匯出oracle 10g的大字段 錯誤現象 用9i的exp匯出時錯誤如下 f oracle bin exp wssw foresee cradle203 file d sb sbxx zb.dmp tables sb sbxx zb export release 9.2.0.1.0 ...
Oracle9i 10g 樹查詢特性
例子 select select id from test where level a.lv start with id a.id connect by id prior f id f id,idfrom select id,level lvfrom test connect by id fid a...
Oracle 10g資料庫管理
oracle 10g資料庫管理 課程介紹 本課程面向企業 oracle 10g 資料庫管理的學員。通過 oracle 10g 資料庫管理課程的系統培訓,使學員能夠在較短的時間內掌握 oralcle10g 資料庫管理和維護的各種技術,從而掌握最新版 oracle 的新特性和 oracle 資料通用技術...