0

I have one table in PostgreSQL which is like this (Img1)

enter image description here

From this table I am trying to achieve this (Img2)

enter image description here

I am trying to do this using CROSSTAB but in doing so I am not able to get Roll No Column. Below is the query that I am using.

SELECT * 
FROM CROSSTAB
('select student, subject, marks from dummy order by 1,2') 
AS FINAL
(
    Student TEXT, 
    Geography NUMERIC,
    History NUMERIC,
    Language NUMERIC,
    Maths NUMERIC,
    Music NUMERIC
);

How to achieve the expected output as I shown in (Img2)?

Naved Ansari
  • 650
  • 2
  • 13
  • 31

2 Answers2

1

You could just use conditional aggregation:

select student,
       max(marks) filter (where subject = 'Music') as music,
       max(marks) filter (where subject = 'Maths') as maths,
       max(marks) filter (where subject = 'History') as history,
       max(marks) filter (where subject = 'Language') as language,
       max(marks) filter (where subject = 'Geography') as geography,
       rollno
from t
group by student, rollno;
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
1

To return "extra" columns, you need the 2-parameter form of the crosstab() function (which is typically what you want anyway):

SELECT * 
FROM  crosstab(
   'SELECT student, roll_no, subject, marks
    FROM   dummy
    ORDER  BY 1'
 , $$SELECT unnest('{Geography, History, Language, Maths, Music}'::text[])$$
   ) AS final (
      "Student"   text
    , "Roll No"   text  -- extra column(s) go here
    , "Geography" int
    , "History"   int
    , "Language"  int
    , "Maths"     int
    , "Music"     int
);

db<>fiddle here

Detailed explanation:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228