For this example I use the dataset as AnthonyJ used in the comments. The explanation for the regular expression can be found in the original post.
SQL> with test as
2 (
3 select 1 id, 'joey,anthony,marvin' str from dual union all
4 select 5 id, 'tony,glenn' str from dual union all
5 select 8 id, 'john' str from dual
6 )
7 select id
8 , str
9 , regexp_substr (str, '[^,]+', 1, rn) split
10 from test
11 cross
12 join (select rownum rn
13 from (select max (length (regexp_replace (str, '[^,]+'))) + 1 mx
14 from test
15 )
16 connect by level <= mx
17 )
18 where regexp_substr (str, '[^,]+', 1, rn) is not null
19 order by id
20 ;
ID STR SPLIT
---------- ------------------- -------------------
1 joey,anthony,marvin joey
1 joey,anthony,marvin marvin
1 joey,anthony,marvin anthony
5 tony,glenn tony
5 tony,glenn glenn
8 john john
The trick here is in lines 11 through 17. The Cross Join is there to create multiple records, but no more than the longest intended individual words (three in this case).
Because each ID would result in three records, which is alright for ID 1, it will also create three records for ID 5 and ID 8. Line 18 removes these extra records.
If you use Oracle 11g, you can also use REGEXP_COUNT instead of the combination of REGEXP_REPLACE and LENGTH, which would look like this:
cross
join (select rownum rn
from (select max (regexp_count (str, ',') + 1) mx
from test
)
connect by level <= mx
)
Regexp_Count


I was looking for something exactly like this. Thanks a lot, it works like a charm.
ReplyDelete