问题描述
我在表中有一列存储一系列数据。有些数据使用连字符分隔,而另一些则使用逗号分隔。我想将数据分成几行。关键是逗号分隔的值在每个逗号之后都被视为单个值,但是对于连字符来说,这意味着一种数据范围。
例如,如果字符串是类似'A1,A2,A4'
的字符串,则表示存在3个值,并将其转换为3行。还有一个类似'A1-A4'
的字符串,它表示有4个值,并将转换为4行,因为连字符代表表示起始值和结束值的值范围。
我能够转换逗号分隔的值,但是不确定如何在oracle中拆分连字符分隔的范围。
SELECT regexp_substr('A1,A4','[^,]+',1,level) as a
FROM dual
CONNECT BY regexp_substr('A1,level) is not null
在ddl之上,将提供的字符串转换为3行。
SELECT regexp_substr('A1-A4','[^-]+',level) as a
FROM dual
CONNECT BY regexp_substr('A1-A4',level) is not null
但是上面的查询应该返回4行,但是我不确定如何实现。 有什么想法吗?
解决方法
假设模式将始终是一对具有相同前缀(此处为“ A”)的值,并且每个值后面都有一个数字,则可以使用其他正则表达式来提取前缀,起始数字和结束数字:>
SELECT
regexp_substr('A1-A4','(.*?)(\d+)-.*?(\d+)',1,null,1) as prefix,to_number(regexp_substr('A1-A4',2)) as start_num,3)) as end_num
FROM dual
PREFIX START_NUM END_NUM
------ --------- ---------
A 1 4
,然后在递归CTE中使用它来获取介于两者之间的值:
WITH rcte (prefix,num,end_num) AS (
SELECT
regexp_substr('A1-A4',1),2)),3))
FROM dual
UNION ALL
SELECT prefix,num + 1,end_num
FROM rcte
WHERE num < end_num
)
SELECT prefix || num as result
FROM rcte
RESULT
------
A1
A2
A3
A4
您可以在一个查询中结合使用这两种方法,进一步假设您在同一字符串中没有混合使用逗号分隔的值和范围; db<>fiddle demo。如果您确实有混合的话,可以将它们串联应用。将以逗号分隔的行转换为行,然后进一步处理那些实际上是连字符范围的新行。
,带有扩展样本数据的完整示例:
with t(n,str) as (
select 1,'A1,A2,A4' from dual union all
select 2,'B1,B4,B7-B11' from dual union all
select 3,'C1,C3,C5-C7' from dual union all
select 4,'XY1,XT3,ZZ5-ZZ7' from dual
)
select *
from t,lateral(
select level part_n,regexp_substr(str,'[^,]+',level) part
from dual
connect by level<=regexp_count(str,]+')
),lateral(
select
level sub_part_n,nvl(
regexp_substr(part,'(\w+)(\d+)[ -]+\1(\d+)',1)
||
(regexp_substr(part,2) + level -1),part
)
as subpart
from dual
connect by level<= regexp_substr(part,3)
- regexp_substr(part,2)
+ 1
)
结果:
N STR PART_N PART SUB_PART_N SUBPART
---------- ----------------- ---------- ---------- ---------- ----------
1 A1,A4 1 A1 1 A1
1 A1,A4 2 A2 1 A2
1 A1,A4 3 A4 1 A4
2 B1,B7-B11 1 B1 1 B1
2 B1,B7-B11 2 B4 1 B4
2 B1,B7-B11 3 B7-B11 1 B7
2 B1,B7-B11 3 B7-B11 2 B8
2 B1,B7-B11 3 B7-B11 3 B9
2 B1,B7-B11 3 B7-B11 4 B10
2 B1,B7-B11 3 B7-B11 5 B11
3 C1,C5-C7 1 C1 1 C1
3 C1,C5-C7 2 C3 1 C3
3 C1,C5-C7 3 C5-C7 1 C5
3 C1,C5-C7 3 C5-C7 2 C6
3 C1,C5-C7 3 C5-C7 3 C7
4 XY1,ZZ5-ZZ7 1 XY1 1 XY1
4 XY1,ZZ5-ZZ7 2 XT3 1 XT3
4 XY1,ZZ5-ZZ7 3 ZZ5-ZZ7 1 ZZ5
4 XY1,ZZ5-ZZ7 3 ZZ5-ZZ7 2 ZZ6
4 XY1,ZZ5-ZZ7 3 ZZ5-ZZ7 3 ZZ7
,
如果应用于具有多行的表,则可以尝试执行以下操作(请参见代码中的注释):
SQL> with test (id,col) as
2 -- sample data
3 (select 1,A4' from dual union all
4 select 2,'BX8-BX11' from dual union all
5 select 3,C4' from dual union all
6 select 4,'D6-D9' from dual
7 ),8 temp as
9 -- split e.g. "BX8-BX11" to "BX",8 and 11
10 (select id,11 regexp_substr(col,'^[[:alpha:]]+') alp,12 to_number(regexp_substr(col,'\d+',1)) num1,13 to_number(regexp_substr(col,2)) num2
14 from test
15 where instr(col,'-') > 0
16 )
17 -- trivial - split comma-separated values to rows
18 select id,19 regexp_substr(col,column_value) val
20 from test cross join table(cast(multiset(select level from dual
21 connect by level <= regexp_count(col,',') + 1
22 ) as sys.odcinumberlist))
23 where instr(col,'-') = 0
24 union all
25 -- create rows for values that are dash-separated
26 select id,27 alp || to_char(num1 + column_value - 1) val
28 from temp cross join table(cast(multiset(select level from dual
29 connect by level <= num2 - num1 + 1
30 ) as sys.odcinumberlist))
31 order by id,val;
ID VAL
---------- ------------------------------------------------
1 A1
1 A2
1 A4
2 BX10
2 BX11
2 BX8
2 BX9
3 C1
3 C4
4 D6
4 D7
4 D8
4 D9
13 rows selected.
SQL>
,
或者:
JLabel label = new JLabel(icon,JLabel.CENTER);
AddImages.add(label);
AddImages.revalidate();
用一系列连续的整数输入,并选择第i个连续的非逗号/连续的非连字符...。
CROSS JOIN