Input
Student_Name | Maths | Science | Social |
---|---|---|---|
A | 20 | 30 | 10 |
B | 10 | 20 | 30 |
Output
Student_Name | max_sub | min_sub |
---|---|---|
A | Science | Social |
B | Social | 20Maths |
I tried
select student_name,max(marks) m1, min(marks) m2
from
(
select student_name, engg, fre, sp from student)
unpivot (marks for subject in(engg, fre, sp)
)
group by student_name;
but no luck
Unpivot, then re-pivot (or, simpler, just aggregate explicitly, as I show below):
with
student(student_name, math, science, social) as (
select 'A', 20, 30, 10 from dual union all
select 'B', 10, 20, 30 from dual
)
select student_name,
max(sub) keep (dense_rank last order by mark nulls first) as max_sub,
min(sub) keep (dense_rank first order by mark nulls last ) as min_sub
from student
unpivot (mark for sub in (math as 'Math', science as 'Science',
social as 'Social'))
group by student_name
;
STUDENT_NAME MAX_SUB MIN_SUB
------------ ------- -------
A Science Social
B Social Math
A few things are missing or plain wrong in your problem specification. First and most important, I do hope that in real life you have a student id column - different students may have the same name. (One can work around that for this specific problem, but not in general.)
Then - you need to specify how null
grades should be treated (what if a student simply doesn't have a grade in Math, for example), and what to show in the case of ties (a student has the same, highest grade in two different subjects). I made one particular set of choices above - they may or may not be right for your use case. Any other choices can be accommodated easily, as soon as you say what they are.
You do not need to UNPIVOT
and then PIVOT
. You can use a CASE
statement and compare the columns values using GREATEST
, for the maximum, and LEAST
, for the minimum:
SELECT student_name,
CASE
WHEN maths = LEAST(maths, science, social) THEN 'Maths'
WHEN science = LEAST(maths, science, social) THEN 'Science'
WHEN social = LEAST(maths, science, social) THEN 'Social'
END AS minimum,
CASE
WHEN maths = GREATEST(maths, science, social) THEN 'Maths'
WHEN science = GREATEST(maths, science, social) THEN 'Science'
WHEN social = GREATEST(maths, science, social) THEN 'Social'
END AS maximum
FROM student;
Which, for the sample data:
CREATE TABLE student (Student_Name, Maths, Science, Social) AS
SELECT 'A', 20, 30, 10 FROM DUAL UNION ALL
SELECT 'B', 10, 20, 30 FROM DUAL UNION ALL
SELECT 'C', 10, 10, 10 FROM DUAL;
Outputs:
STUDENT_NAME MINIMUM MAXIMUM A Social Science B Maths Social C Maths Maths
If you want to show all the subjects in the case of a tie for minimum or maximum then you can use:
SELECT student_name,
LTRIM(
CASE WHEN maths = LEAST(maths, science, social) THEN 'Maths' END
|| CASE WHEN science = LEAST(maths, science, social) THEN ', Science' END
|| CASE WHEN social = LEAST(maths, science, social) THEN ', Social' END,
', '
) AS minimum,
LTRIM(
CASE WHEN maths = GREATEST(maths, science, social) THEN 'Maths' END
|| CASE WHEN science = GREATEST(maths, science, social) THEN ', Science' END
|| CASE WHEN social = GREATEST(maths, science, social) THEN ', Social' END,
', '
) AS maximum
FROM student;
Which outputs:
STUDENT_NAME MINIMUM MAXIMUM A Social Science B Maths Social C Maths, Science, Social Maths, Science, Social
db<>fiddle here
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.