oracle sql:split string并返回其他不匹配的部分

时间:2014-06-26 21:05:31

标签: sql regex oracle split

我有一个看起来像这样的表:

AMT       TYPE
100       red, yellow, green, purple
200       red, green, blue, yellow
90        pink, blue, light red
......

我想要的是按颜色添加金额。例如,最终输出应为:

AMT       TYPE
300       red
300       yellow
300       green
290       blue
190       other

请注意1.我不想在light red中加入red 2.我希望将除红色,黄色,绿色,蓝色以外的所有颜色都包含在一个新类别"其他"。

我目前的代码是

select sum(red), ... from (
      select
        case when trim(regexp_substr(type, red',1,1,'i')) is not null
             then amt
        else 0 end as red
        ......
      from mytable)

但它并没有解决我之前提到的问题。我也尝试了以下方法,但它变得如此缓慢,以至于它永远不会结束。 (或者这段代码可能有错误?)

select color, sum(amt)
from (
     select trim(regexp_substr(type,'[^,]+', 1, level)) as color
     from mytable
     connect by level <= regexp_count(type, ',')+1)
group by color

我该如何解决这个问题?

谢谢!

2 个答案:

答案 0 :(得分:0)

你有完整的颜色列表吗?

想象一下你做到了。让table color(name varchar2(...) not null primary key)列出每种颜色。

然后你可以这样写:

select 
  color.name, sum(crazy_table.amt)
from
  color, crazy_table -- the latter is your original data
where
  crazy_table.type like '%, ' || color.name -- at the end of string
  or 
  crazy_table.type like color.name || ', %' -- at the start of string
  or  crazy_table.type like '%, ' || color.name || ', %' -- middle
  or
  crazy_table.type = color.name -- single entry, no commas
  or
  color.name = 'other' and not exists ( -- no known color matches
    select 1 from color as c2
    where instr(crazy_table.type, c2.name) > 0
  )
group by color.name

它会完全扫描crazy_table,这可能是大的,在color表上进行索引查找,这可能要小得多,所以性能应该没问题。

答案 1 :(得分:0)

以下查询可以获得所需的结果。它

1.首先根据OTN论坛上convert comma separated string into rows给出的737905解决方案,将颜色值分成不同的行。

2.使用CASE陈述来指定其他&#39;除红色,黄色,绿色和蓝色外的颜色类别。

3.按颜色分组

4.按预先确定的颜色顺序排序

WITH SPLIT_COLORS AS
  (
    SELECT
      AMT,
      TRIM(EXTRACT(column_value,'/e/text()')) COLOR
    FROM
      mytable x,
      TABLE(XMLSEQUENCE(EXTRACT(XMLTYPE('<ROW><e>'
      ||REPLACE(type,',','</e><e>')
      ||'</e></ROW>'),'//e')))
  )
SELECT
  CASE
    WHEN color NOT IN ('red', 'yellow', 'green', 'blue') THEN 'other'
    ELSE color
  END AS color,
  SUM(amt) amt
FROM
  SPLIT_COLORS
GROUP BY
  CASE
    WHEN color NOT IN ('red', 'yellow', 'green', 'blue') THEN 'other'
    ELSE color
  END
ORDER BY
  CASE color
    WHEN 'red' THEN 1
    WHEN 'yellow' THEN 2
    WHEN 'green' THEN 3
    WHEN 'blue' THEN 4
    ELSE 5
  END;

您只能测试第一部分的输出(CTE&#39; s - 公用表格式),如下所示:

WITH SPLIT_COLORS AS
  (
    SELECT
      AMT,
      TRIM(EXTRACT(column_value,'/e/text()')) COLOR
    FROM
      mytable x,
      TABLE(XMLSEQUENCE(EXTRACT(XMLTYPE('<ROW><e>'
      ||REPLACE(type,',','</e><e>')
      ||'</e></ROW>'),'//e')))
  )
SELECT *
FROM SPLIT_COLORS;