Tito
Tito

Reputation: 671

How to create columns for different fields without applying the pivoting function

So i have a question for the tough hearted! I have had an issue with this concept for awhile and I need it to be cleared... The following code shows students who have more than 1 language

SELECT DISTINCT s.studentnumber as studentnr, 
    p.firstname AS name,
    sl.gradenumber as gradenumber,
    string_agg(DISTINCT l.text, ', ') as languages

FROM student s
    JOIN pupil p ON p.id = s.pupilid    
    JOIN pupillanguage pl on pl.pupilid = p.id
    JOIN language l on l.id = pl.languageid
    JOIN schoollevel sl ON sl.id = p.schoollevelid

GROUP BY s.studentnumber, 
    p.firstname 

Result

result1

Now my question is simple yet I'm not sure how the answer would be... I want to split up those languages and put them in seperate fields so its looks something like this

Wanted Result

wantedresult

There is also 1 major issue. This is using Postgresql 9.3 which doesnt now allow grouping set or rollup or cube. I tried this code however and its not working correctly, im not sure how to deal with it and im not sure how to go forward about it...

(select distinct l.text 
            from language 
            join pupillanguage pl2 on pl2.languageid = language.id 
            join pupil on p.id = pl2.personid
            limit 1) as language1

This is how the Tables looks like

Language Table 
iD                   PK
shorttext            char varying
text                 char varying

PupilLanguage Table

id                   PK
languageid           FK
personid             FK
displayorder         int

Upvotes: 0

Views: 113

Answers (2)

user330315
user330315

Reputation:

If you have a fixed number of columns, you can use an array:

select studentnr, name, gradenumber, 
       languages[1] as language_1,
       languages[2] as language_2,
       languages[3] as language_3,
       languages[4] as language_4,
       languages[5] as language_5
FROM (       
  SELECT s.studentnumber as studentnr, 
         p.firstname AS name,
         sl.gradenumber as gradenumber,
         array_agg(DISTINCT l.text) as languages
  FROM student s
      JOIN pupil p ON p.id = s.pupilid    
      JOIN pupillanguage pl on pl.pupilid = p.id
      JOIN language l on l.id = pl.languageid
      JOIN schoollevel sl ON sl.id = p.schoollevelid
  GROUP BY s.studentnumber, p.firstname
) t

Note that distinct is usually not needed when you use group by

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1270663

A SQL query returns a fixed number of columns. If you want just three additional columns, then you can use dynamic aggregation:

with t as (
      SELECT s.studentnumber as studentnr, p.firstname AS name,
             sl.gradenumber as gradenumber, l.text as language,
             dense_rank() over (partition by s.studentnumber, p.firstname, sl.gradenumber order by l.text) as seqnum
      FROM student s JOIN 
           pupil p
           ON p.id = s.pupilid JOIN
           pupillanguage pl 
           ON pl.pupilid = p.id JOIN
           language l 
           ON l.id = pl.languageid JOIN
           schoollevel sl
           ON sl.id = p.schoollevelid
     )
select studentnr, name, gradenumber,
       max(case when seqnum = 1 then language end) as language_1,
       max(case when seqnum = 2 then language end) as language_2,
       max(case when seqnum = 3 then language end) as language_3
from t
group by studentnr, name, gradenumber;

However, if you want a variable number, then you need crosstab or dynamic SQL. I might also suggest that you consider arrays instead.

Upvotes: 1

Related Questions