split data in a single column into multiple columns in oracle
my_table :
Name | Value |
---|---|
item_1 | AB |
item_2 | 2 |
item_3 | B1 |
item_1 | CD |
item_1 | EF |
item_2 | 3 |
item_3 | B2 |
item_4 | ZZ |
required output:
item_1 | item_2 | item_3 | item_4 |
---|---|---|---|
AB | 2 | B1 | ZZ |
CD | 3 | B2 | NULL |
EF | NULL | NULL | NULL |
SQL query :
with item_1 as (select value from my_table where name = 'item_1'),
item_2 as (select value from my_table where name = 'item_2'),
item_3 as (select value from my_table where name = 'item_3'),
item_4 as (select value from my_table where name = 'item_4')
select item_1.value, item_2.value,item_3.value, item_4.value from item_1 cross join item_2 cross join item_3 cross join item_4;
If I am using pivot along with MAX aggregate function, the query will display only max values of the corresponding items instead of displaying all the values.
Is there any way to split a single column into multiple columns(using where condition as mentioned in the above query) without cross join.
Solution 1:
Use ROW_NUMBER
and then PIVOT
:
SELECT item_1,
item_2,
item_3,
item_4
FROM (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY ROWNUM) AS rn
FROM table_name t
)
PIVOT (
MAX(value) FOR name IN (
'item_1' AS item_1,
'item_2' AS item_2,
'item_3' AS item_3,
'item_4' AS item_4
)
)
Which, for the sample data:
CREATE TABLE table_name (Name, Value) AS
SELECT 'item_1', 'AB' FROM DUAL UNION ALL
SELECT 'item_2', '2' FROM DUAL UNION ALL
SELECT 'item_3', 'B1' FROM DUAL UNION ALL
SELECT 'item_1', 'CD' FROM DUAL UNION ALL
SELECT 'item_1', 'EF' FROM DUAL UNION ALL
SELECT 'item_2', '3' FROM DUAL UNION ALL
SELECT 'item_3', 'B2' FROM DUAL UNION ALL
SELECT 'item_4', 'ZZ' FROM DUAL;
Outputs:
ITEM_1 ITEM_2 ITEM_3 ITEM_4 AB 2 B1 ZZ CD 3 B2 null EF null null null
db<>fiddle here
Solution 2:
How about this?
DF
column is calculated by row_number
analytic function which partitions by each name (and sorts by value). It is ignored from the final column list, but its role is crucial in the GROUP BY
clause.
SQL> with test (name, value) as
2 (select 'item_1', 'AB' from dual union all
3 select 'item_2', '2' from dual union all
4 select 'item_3', 'B1' from dual union all
5 select 'item_1', 'CD' from dual union all
6 select 'item_1', 'EF' from dual union all
7 select 'item_2', '3' from dual union all
8 select 'item_3', 'B2' from dual union all
9 select 'item_4', 'ZZ' from dual
10 ),
11 temp as
12 (select name, value,
13 row_number() over (partition by name order by value) df
14 from test
15 )
16 select
17 max(case when name = 'item_1' then value end) item_1,
18 max(case when name = 'item_2' then value end) item_2,
19 max(case when name = 'item_3' then value end) item_3,
20 max(case when name = 'item_4' then value end) item_4
21 from temp
22 group by df;
ITEM_1 ITEM_2 ITEM_3 ITEM_4
------ ------ ------ ------
AB 2 B1 ZZ
CD 3 B2
EF
SQL>