I have the data in the format
data
column1 column2
abcd ~123~abd~
The data in column 2 is separated by ~
the output should be in the format in two rows
column1 column2
abcd 123
abcd abd
can some please help.
I have the data in the format
data
column1 column2
abcd ~123~abd~
The data in column 2 is separated by ~
the output should be in the format in two rows
column1 column2
abcd 123
abcd abd
can some please help.
Oracle does not have a built-in string tokenizer but it's easy enough to build our own. There are several different solutions (both on SO and the wider interwebs) but I'll use a function, string_tokenizer()
, I posted some while back in this other answer.
with data as ( select column1
, trim(both '~' from column2) as column2
from your_table )
select data.column1
, t.column_value
from data
, table ( string_tokenizer (data.column2, '~'))t;
By the way the TRIM() call is necessary to remove the leading and trailing instances of ~
(although perhaps the tokenizer function could handle that instead. Hmmm...)
with sample data as
SQL> select * from your_table;
COLUMN1 COLUMN2
-------------------- --------------------
abcd ~123~abd~
foo ~test~test2~
foo2 ~test~
Model clause (10g+):
SQL> with foo as (select rownum id, column1, column2, length(regexp_replace(column2, '[^~]', ''))-1 elem_cnt
2 from your_table)
3 select column1, elem
4 from (select column1, elem, f
5 from foo
6 model partition by(id)
7 dimension by(0 as f)
8 measures(column1, column2, elem_cnt,
9 cast('' as varchar2(4000)) elem)
10 rules (elem [for f from 0 to elem_cnt[0]-1 increment 1]
11 = substr(column2[0], instr(column2[0], '~', 1, cv(f)+1) + 1,
12 instr(column2[0], '~', 1, cv(f)+2) - instr(column2[0], '~', 1, cv(f)+1) - 1),
13 column1[any] = column1[0]))
14 order by f;
COLUMN1 ELEM
-------------------- --------------------
abcd 123
abcd abd
foo test
foo test2
foo2 test
or 11g recursive subquery factoring:
SQL> with data (id, column1, column2, elem, elem_cnt, curr_elem)
2 as (select rownum id, column1, column2,
3 substr(column2, instr(column2, '~') + 1,
4 instr(column2, '~', 1, 2) - instr(column2, '~') - 1) elem,
5 length(regexp_replace(column2, '[^~]', ''))-1 elem_cnt,
6 1 as curr_elem
7 from your_table
8 union all
9 select rownum id, column1, column2,
10 substr(column2, instr(column2, '~', 1, elem_cnt) + 1,
11 instr(column2, '~', 1, elem_cnt+1) - instr(column2, '~', 1, elem_cnt) - 1) elem,
12 length(regexp_replace(column2, '[^~]', ''))-1 elem_cnt,
13 curr_elem + 1
14 from data
15 where curr_elem < elem_cnt)
16 select column1, elem
17 from data
18 order by column1, curr_elem;
COLUMN1 ELEM
-------------------- --------------------
abcd 123
abcd abd
foo test
foo test2
foo2 test