简体   繁体   中英

Rows to columns using PIVOT function (Oracle)

I'm attempting to create a query to transpose rows into columns using the PIVOT function. I have a table in this form (this is just the partial view, the table contains more than 30 columns).

ID      SUBJECT  GRADE
000442  WRI001   C-
000442  PHY104   C
000442  MTH111   B
000442  MTH111   W
000442  MTH111   W
000442  PHY104   W

Expected result:

ID      'WRI001'   'MTH111'   'PHY104'
000442   C-         B,W,W      C,W

Query used:

select * from (
   select ID,
          SUBJECT,GRADE
   from SECOND_YEAR_COMP
             )
pivot 
(
   MAX(GRADE)
   for SUBJECT in
   ('MTH111',
    'WRI001',
    'PHY104')
);

Query Output:

ID      'WRI001'   'MTH111'   'PHY104'
000442   C-         W          W

I know because of MAX(GRADE) I am getting single grade for each subject. Is there any way to get all the grades for the subject (as my expected result give above).

You can use listagg() and conditional aggregation:

select id,
    listagg(case when subject = 'WRI001' then grade end) WRI001,
    listagg(case when subject = 'WRI001' then grade end) WRI001,
    listagg(case when subject = 'PHY104' then grade end) PHY104
from second_year_comp
group by id

You can control the order in which the grades appear in the concatenatd string with the within group clause. Say you want to order by grade, then:

select id,
    listagg(case when subject = 'WRI001' then grade end) within group(order by grade) WRI001,
    listagg(case when subject = 'WRI001' then grade end) within group(order by grade) WRI001,
    listagg(case when subject = 'PHY104' then grade end) within group(order by grade) PHY104
from second_year_comp
group by id

You were nearly done - the only missing point is - you should replace the MAX aggregate function with the LISTAGG function using the full syntax in the PIVOT clause .

Additionaly I adjusted the pivot column names to get nice names (without apostrophes).

See example below:

select * from (
   select ID,
          SUBJECT,GRADE
   from tab
             )
pivot 
(
   LISTAGG(GRADE,',') within group (order by GRADE)
   for SUBJECT in
   ('MTH111' as MTH111,
    'WRI001' as WRI001,
    'PHY104' as PHY104)
)

Result as expected

ID     MTH111     WRI001     PHY104    
------ ---------- ---------- ----------
000442 B,W,W      C-         C,W    

You can use listagg() for string aggregation and then apply pivot

With cte as
(
SELECT ID, SUBJECT,LISTAGG(GRADE, ',') WITHIN GROUP (ORDER BY grade) AS grade
FROM   tablename
GROUP BY id,SUBJECT
)
select * from (
   select ID,SUBJECT,GRADE from cte)
pivot 
(
   MAX(GRADE)
   for SUBJECT in ('MTH111','WRI001','PHY104')
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM