将列拆分为多行

时间:2010-09-14 21:37:54

标签: sql oracle oracle10g tokenize

我的表包含一个包含多个以逗号(,)分隔的值的列,并希望将其拆分,因此我将earch Site放在自己的行上,但前面的数字相同。

所以我的选择将来自此输入

table Sitetable

Number             Site
952240             2-78,2-89                                                                                                                                                                      
952423             2-78,2-83,8-34

创建此输出

Number             Site
952240             2-78
952240             2-89
952423             2-78 
952423             2-83
952423             8-34

我找到了一些我认为会起作用的东西但是没有......

select Number, substr(
    Site, 
    instr(','||Site,',',1,seq),
    instr(','||Site||',',',',1,seq+1) - instr(','||Site,',',1,seq)-1)  Site
from Sitetable,(select level seq from dual connect by level <= 100) seqgen
where instr(','||Site,',',1,seq+1) > 0

Edit2:我看到我实际上有一部分工作选择(我是一个糟糕的测试人员:(),上面的一个工作,但唯一的问题是它失去了最后的网站值,但我试图工作有点......

Edit3:现在正在运作

select Number, substr(
Site, 
instr(','||Site,',',1,seq),
instr(','||Site||',',',',1,seq+1) - instr(','||Site,',',1,seq)-1)  Site
from Sitetable,(select level seq from dual connect by level <= 100) seqgen
where instr(','||Site,',',1,seq) > 0

5 个答案:

答案 0 :(得分:4)

正确答案是。

select Number, substr(
Site, 
instr(','||Site,',',1,seq),
instr(','||Site||',',',',1,seq+1) - instr(','||Site,',',1,seq)-1)  Site
from Sitetable,(select level seq from dual connect by level <= 100) seqgen
where instr(','||Site,',',1,seq) > 0

答案 1 :(得分:3)

您是否尝试过Michael How to best split csv strings in oracle 9i

的答案?
create or replace function splitter_count(str in varchar2, delim in char) return int as
val int;
begin
  val := length(replace(str, delim, delim || ' '));
  return val - length(str); 
end;

create type token_list is varray(100) of varchar2(200);

CREATE or replace function tokenize (str varchar2, delim char) return token_list as
ret token_list;
target int;
i int;
this_delim int;
last_delim int;
BEGIN
  ret := token_list();
  i := 1;
  last_delim := 0;
  target := splitter_count(str, delim);
  while i <= target
  loop
    ret.extend();
    this_delim := instr(str, delim, 1, i);
    ret(i):= substr(str, last_delim + 1, this_delim - last_delim -1);
    i := i + 1;
    last_delim := this_delim;
  end loop;
  ret.extend();
  ret(i):= substr(str, last_delim + 1);
  return ret;
end;

答案 2 :(得分:2)

------------创建结果表----------------------------- --------------

创建table resulTable(

cnumber number,

网站varchar2(1000)

);

------------创建拆分程序----------------------------- ---------

/ 在这里我用数字代替数字:2-78由s2ss78s代替使用
DBMS_UTILITY.comma_to_table(它不适用于数字)
/

创建或替换过程split_list_to_rows(num number,plist varchar2)为

ptablen BINARY_INTEGER;

ptab DBMS_UTILITY.uncl_array;

开始

DBMS_UTILITY.comma_to_table(

list =&gt;替换(替换(CONCAT('s',plist),',',',s'),' - ','ss'),

tablen =&gt; ptablen,

tab =&gt; PTAB);

FOR i IN 1 .. ptablen LOOP

插入INTO结果值(num,replace(ltrim(ptab(i),'s'),'ss',' - '));

END LOOP;

END;

------------ PL / SQL阻止每行执行程序-------------------

开始

for i in(select cnumber,Site from Sitetable)

split_list_to_rows(i.cnumber,i.Site);

结束循环;

端;

------------------------查看结果----------------- ----------------------

从resulTable中选择*;

答案 3 :(得分:0)

我认为您的最大限制为100个逗号分隔值,这是不必要的,但在您的情况下可能没有害处。

而不是

from Sitetable,(select level seq from dual connect by level <= 100) 

这适用于任意数量的值(级别受限于最大逗号数)。

from Sitetable,(select level seq from dual connect by level <=  (select max((LENGTH(site)-LENGTH(REPLACE(site,',', '' ))) + 1) from sitetable)

答案 4 :(得分:-1)

使用交叉连接:

选择编号,站点编号
从站点表 交叉应用STRING_SPLIT(Site,',');