我同意这是一个非常糟糕的设计。
如果您不能更改该设计,请尝试以下方法:
select distinct id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
from tbl1
connect by regexp_substr(value, '[^,]+', 1, level) is not null
order by id, level;
输出
id value level
1 AA 1
1 UT 2
1 BT 3
1 SK 4
1 SX 5
2 AA 1
2 UT 2
2 SX 3
3 UT 1
3 SK 2
3 SX 3
3 ZF 4
感谢这篇文章
为了更优雅和高效地去除重复项(感谢@mathguy)
select id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
from tbl1
connect by regexp_substr(value, '[^,]+', 1, level) is not null
and PRIOR id = id
and PRIOR SYS_GUID() is not null
order by id, level;
如果你想要一种更“ANSI”化的方法,请使用CTE:
with t (id,res,val,lev) as (
select id, trim(regexp_substr(value,'[^,]+', 1, 1 )) res, value as val, 1 as lev
from tbl1
where regexp_substr(value, '[^,]+', 1, 1) is not null
union all
select id, trim(regexp_substr(val,'[^,]+', 1, lev+1) ) res, val, lev+1 as lev
from t
where regexp_substr(val, '[^,]+', 1, lev+1) is not null
)
select id, res,lev
from t
order by id, lev;
输出
id val lev
1 AA 1
1 UT 2
1 BT 3
1 SK 4
1 SX 5
2 AA 1
2 UT 2
2 SX 3
3 UT 1
3 SK 2
3 SX 3
3 ZF 4
另一种MT0的递归方法,但不使用正则表达式:
WITH t ( id, value, start_pos, end_pos ) AS
( SELECT id, value, 1, INSTR( value, ',' ) FROM tbl1
UNION ALL
SELECT id,
value,
end_pos + 1,
INSTR( value, ',', end_pos + 1 )
FROM t
WHERE end_pos > 0
)
SELECT id,
SUBSTR( value, start_pos, DECODE( end_pos, 0, LENGTH( value ) + 1, end_pos ) - start_pos ) AS value
FROM t
ORDER BY id,
start_pos;
我已经尝试了三种方法,使用了一个30000行的数据集和返回了118104行,并得到了以下平均结果:
- 我的递归方法:5秒
- MT0方法:4秒
- Mathguy方法:16秒
- MT0递归方法无正则表达式:3.45秒
@Mathguy也测试了更大的数据集:
在所有情况下,递归查询(我只测试了具有常规substr和instr的查询)效果更好,因子为2到5。这里是字符串/每个字符串的标记数和层次结构与递归执行时间的组合,层次结构排在前面。所有时间都以秒为单位。
- 30,000 x 4: 5 / 1.
- 30,000 x 10: 15 / 3.
- 30,000 x 25: 56 / 37.
- 5,000 x 50: 33 / 14.
- 5,000 x 100: 160 / 81.
- 10,000 x 200: 1,924 / 772