将列拆分为多行

Posted

技术标签:

【中文标题】将列拆分为多行【英文标题】:Split column to multiple rows 【发布时间】:2010-09-14 21:37:53 【问题描述】:

我有一个表格,其中有一列包含多个用逗号 (,) 分隔的值,我想将其拆分,以便将每个站点放在自己的行上,但前面的数字相同。

所以我的选择会来自这个输入

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

【问题讨论】:

SQL query to translate a list of numbers matched against several ranges, to a list of values 的可能重复项 查看我对我确定为可能重复的另一篇 SO 帖子的回答。它是您的问题的 10g 解决方案。 我认为我的选择现在工作得更好了 有没有办法在 SQL Server 2008 中做到这一点?? 【参考方案1】:

正确答案是。

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

【讨论】:

【参考方案2】:

你试过 Michael Sofaer 对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;

【讨论】:

【参考方案3】:

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

创建表resulTable(

cnumber,

网站 varchar2(1000)

);

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

/这里我用 s2ss78s 替换了数字,例如:2-78 以供使用 DBMS_UTILITY.comma_to_table(对数字不起作用)/

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

ptablen BINARY_INTEGER;

ptab DBMS_UTILITY.uncl_array;

开始

DBMS_UTILITY.comma_to_table (

list => replace(replace(CONCAT('s', plist),',',',s'),'-','ss'),

tablen => ptablen,

tab => ptab);

FOR i IN 1 .. ptablen 循环

insert INTO resulTable VALUES (num,replace(ltrim(ptab(i),'s'),'ss','-'));

结束循环;

结束;

------------PL/SQL 块为每一行执行过程--------

开始

for i in (select cnumber,Site from Sitetable)

循环

split_list_to_rows(i.cnumber,i.Site);

结束循环;

结束;

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

从结果表中选择 *;

【讨论】:

【参考方案4】:

我认为您的最大限制为 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)

【讨论】:

【参考方案5】:

使用交叉连接:

选择编号,站点编号 从站点表 CROSS APPLY STRING_SPLIT(Site, ',');

【讨论】:

以上是关于将列拆分为多行的主要内容,如果未能解决你的问题,请参考以下文章

熊猫:将列中的列表拆分为多行[重复]

Oracle 将列分隔为多行

如何将多行字符串拆分为多行?

将列内包含 JSON 数组的行扩展为多行

Impala:根据日期和时间将单行拆分为多行

将行拆分为多行 PL/SQL