Reputation: 171
I had an below table
y TABLE
id val
-- ---
1 A
1 B
1 C
2 B
2 C
3 A
Need output like below
sno val1 va2 val3
----- ---- ----- ------
1 A B C
2 B C -
3 A - -
I wrote query with self join like
SELECT t1.id as sno, t1.val as val1, t2.val as va2, t3.val as val3
FROM y t1 JOIN y t2 ON t1.id = t2.id
JOIN y t3 ON t2.id = t3.id
ORDER BY 1,2,3,4;
But i returns like Cartesian join. How to get proper result.
Upvotes: 0
Views: 294
Reputation: 35900
If you really want to achieve it using the self join then you need to use group by
and self join
as following:
SELECT t1.id as sno, min(t1.val) as val1, min(t2.val) as va2, min(t3.val) as val3
FROM y t1
LEFT JOIN y t2 ON t1.id = t2.id AND t1.val < t2.val
LEFT JOIN y t3 ON t2.id = t3.id And t2.val < t3.val
Group by t1.id
Cheers!!
Upvotes: 1
Reputation:
Depending on your Oracle version, you can solve this in different ways. You can fix your self-join (you need left outer joins, not inner joins like you have - with inner joins you will only get the id's that have all three values in the input table, even after you fix the rest of the code). You can use conditional aggregation, as Gordon Linoff has shown; this is how pivoting (the name of the operation you are asking about) used to be done in Oracle up to version 10.2. Since version 11.1 you can do the same with the pivot
operator.
Since Oracle 12.1, you can do the same with the match_recognize
clause. Here is how:
create table y (id, val) as
select 1, 'A' from dual union all
select 1, 'B' from dual union all
select 1, 'C' from dual union all
select 2, 'B' from dual union all
select 2, 'C' from dual union all
select 3, 'A' from dual
;
select id, val1, val2, val3
from y
match_recognize(
partition by id
order by val
measures r1.val as val1, r2.val as val2, r3.val as val3
pattern (^ r1 r2? r3?)
define r1 as null is null
);
ID VAL1 VAL2 VAL3
---- ---- ---- ----
1 A B C
2 B C
3 A
Upvotes: 1
Reputation: 1269743
You can use row_number()
and conditional aggregation:
select id,
max(case when seqnum = 1 then val end) as val_1,
max(case when seqnum = 2 then val end) as val_2,
max(case when seqnum = 3 then val end) as val_3
from (select t.*
row_number() over (partition by id order by val) as seqnum
from t
) t
group by id;
Upvotes: 2