4

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).

1
  • The output you show is not the output from your query. That is because the columns in the output will follow exactly the order in the IN list of the PIVOT clause (unless you have an ORDER BY at the end of your query, which you don't). Commented Oct 16, 2020 at 15:44

3 Answers 3

3

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
Sign up to request clarification or add additional context in comments.

1 Comment

This is correct - but since the OP was already using the PIVOT operator, why not show the solution using LISTAGG in PIVOT?
1

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')
);

1 Comment

Why do the aggregation separate from pivoting? Both are aggregate operations; PIVOT can handle LISTAGG as the aggregate function perfectly well. Not a good answer in my opinion (reflected in downvote).
0

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    

1 Comment

Almost as expected; the OP shows a different output (which, as I explain in a comment below his question, is not the output from the query he shared with us). Having to do with the column order in the output - the same as the order in the IN list of PIVOT.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.