Maximum mark in Subject with Staff name - sql

Write a query to display list of staff name, subject name handled, maximum mark scored in that subject. Give an alias to the maximum mark as max_mark. Sort the result based on maximum mark in descending.
This is the schema diagram.
This is the code I have tried.
select distinct
staff_name,
subject_name,
max(value) over (partition by sb.staff_id) as max_mark
from subject sb
inner join staff st
on st.staff_id=sb.staff_id
inner join mark m
on m.subject_id=sb.subject_id
order by max_mark desc;
I was abled to pass one testcase but I could not abled to pass second testcase and I don't know what second testcase is and also I am not getting what I have done wrong in my above code.Is there any way of getting solution for this problem.

It seems that You are looking for the following query:
SELECT
ST.STAFF_NAME,
SB.SUBJECT_NAME,
MAX(M.VALUE) AS MAX_MARK
FROM
STAFF ST
JOIN SUBJECT SB ON SB.STAFF_ID = ST.STAFF_ID
JOIN MARK M ON M.SUBJECT_ID = SB.SUBJECT_ID
GROUP BY
ST.STAFF_ID,
ST.STAFF_NAME,
SB.SUBJECT_ID,
SB.SUBJECT_NAME
ORDER BY
MAX_MARK DESC;

I think that you want aggregation:
select
st.staff_name,
su.subject_name,
max(ma.value) as max_mark
from subject su
inner join staff st on st.staff_id = sb.staff_id
inner join mark ma on ma.subject_id = su.subject_id
group by st.staff_id, st.staff_name, su.subject_id, su.subject_name
order by max_mark desc;

You can use window functions:
select staff_name, subject_name, max_mark
from (select st.staff_name, su.subject_name, ma.value as max_mark,
row_number() over (partition by st.staff_name order by ma.value desc) as seqnum
from subject su join
staff st
on st.staff_id = sb.staff_id join
mark ma
on ma.subject_id = su.subject_id
) s
order by max_mark desc;
You can also use your method (select distinct with window functions) . . . but you have to deal with subject_name:
select distinct staff_name,
first_value(subject_name) over (partition by sb.staff_id order by value desc) as subject_name
max(value) over (partition by sb.staff_id) as max_mark
from subject sb
inner join staff st
on st.staff_id=sb.staff_id
inner join mark m
on m.subject_id=sb.subject_id
order by max_mark desc;

Related

How could I use the select statement on feature from a subquery ? (Postgree)

I'm training for an interview and trying to solve a query, I would like to find for each city who is the client who spent the most. I got the good result the max spent by city but I get an error when I'm trying to retrieve the name and lastname of my customer who spent this amount. Is there an efficient way to do it ? Thank you!
select max(total_payment),X.city, X.firstname, X.lastname
from (
select sum(amount) as total_payment, c.customer_id, cit.city_id, cit.city as city, c.first_name as firstname, c.last_name as lastname
from payment p
inner join customer as c on p.customer_id=c.customer_id
inner join address as ad on c.address_id=ad.address_id
inner join city as cit on ad.city_id=cit.city_id
group by c.customer_id, cit.city_id
order by city
) as X
group by X.city
Target result column:
The name and last name of the customer who spent the most for each city.
120,Paris,Nicolas, Dupont
130, Madrid, Raul, Garcia
70, London,Dave, Goldman
You want window functions:
select cc.*
from (select sum(p.amount) as total_payment, c.customer_id, cit.city_id,
cit.city as city, c.first_name as firstname, c.last_name as lastname,
row_number() over (partition by cit.city order by sum(p.amount) desc) as seqnum
from payment p join
customer c
on p.customer_id = c.customer_id join
address ad
on c.address_id = ad.address_id join
city cit
on ad.city_id = cit.city_id
group by c.customer_id, cit.city_id
) cc
where seqnum = 1;
Note that your query has two errors that should fail any interview:
You are using ORDER BY in a subquery. According to the standard and most databases, ORDER BY is either not allowed or ignored.
In your outer query, the GROUP BY columns are inconsistent with the unaggregated SELECT columns. Once again, this violates the standard and most databases return a syntax error.

Get a column without adding it to the group by

select year, gender, max(nHospitalizations) from (select TO_CHAR(i.since, 'YYYY') as year, u.gender, h.name,count(h.name) as nHospitalizations from hospital h
join hospitalization i on i.hospital = h.name
join person u on i.person = u.numberID
group by TO_CHAR(i.since, 'YYYY'), u.gender, h.name)
group by year, gender
order by year desc, gender asc
;
I have this query, and it's pretty much doing what I want it too, except, I want to know the hospital name with the most hospitalizations per year, but when I add the h.name to the select, SQL makes me add it to the outer group by, which would mean I would be getting the count per year, gender and hospital name like in the subquery, instead of the hospital with most hospitalizations per year and gender, how can I add the h.name to the outer query without adding it to the outer group by?
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
You want to use window functions for this:
select *
from (select count(*) as nHospitalizations, to_char(i.since, 'YYYY') as year,
u.gender, h.name,
row_number() over (partition by min(i.since) order by count(*) desc) as seqnum
from hospital h join
hospitalization i
i.hospital = h.name join
person u
on i.person = u.numberID
group by TO_CHAR(i.since, 'YYYY'), u.gender, h.name
) x
where serqnum = 1

How can I show the maximum score of each department with their names

I can select maximum the score of each department but I can't show the name of each person associated with the max score.
I tried to select the name and the maximum grade (with maximum function) but it doesn't work:
select max(stgrade)as highscore,StName,DepName --department
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid
group by DepName,StName
order by DepName,highscore desc
You may try this...
select * from ( select rank() over (partition by DepName order by stgrade desc) as Slno, stgrade, stname, DepName
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid ) as dep where dep.slno=1
First create rank() in decreasing order of grade for individual department. then select top record for same.
Note: Use RANK() or DENSE_RANK(), both will work fine for top 1 record, while if you want to select n highest grade then use DENSE_RANK(), at the last for slno pass n'th record you want to select.
Always hard to do theory selects, but while DarkRob's solution is good, it will remove students if for instance two people are best. This is why I love using cross apply:
select
d.Depname
, s.StName
, g.stgrade
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on
d.DepID=l.LessonID
inner join TBL_GRADES g on
g.lessonid=l.LessonID
inner join TBL_STUDENT s on
s.STID=g.stid
cross apply (
select
sub_d.DepID
, max(sub_g.stgrade) as maxgrade
from TBL_DEPARTMANTS sub_d
inner join TBL_LESSONS sub_l on
sub_d.DepID=sub_l.LessonID
inner join TBL_GRADES sub_g on
sub_g.lessonid=sub_l.LessonID
where sub_d.Dep_ID = d.Dep_ID
group by sub_d.DepID
) as sub
where g.stgrade = sub.maxgrade
This way you will get all the people with max grade per department and not just one.

SQL on Oracle: Already joined two tables, now i want another column from another table(another join)

I have three tables;
1. Students - id, name
2. Subjects - sid,sname
3. Results - id,sid,marks (id and sid are foreign keys referenced by the two tables above)
Now, i perform
SELECT s.sname AS SubjectName, MAX(r.marks) AS MaxMarks
FROM subjects s, results r
WHERE s.sid=r.sid
GROUP BY r.sid, s.sname
ORDER BY r.sid
and i get The Subject Name with the maximum marks scored in them.
Now further, i also want the student name that has scored these max marks.
So i tried adding the column r.id, didn't work. I tried adding the table students in this query. I'm probably goofing up with the grouping after adding the table or something?
I did this
SELECT r.id AS StudentID, s.sname AS SubjectName, MAX(r.marks) AS MaxMarks
FROM subjects s, results r
WHERE s.sid=r.sid
GROUP BY r.sid, s.sname, r.id
ORDER BY r.sid
and i got each StudentID, with repeated subjects and the marks scored.
Whereas what i basically want is the student who has scored the highest in each subject.
you may use ROW_NUMBER() to tag the student who marked the highest on each subject
SELECT st.name,
sj.sname,
r.marks
FROM (SELECT id,
sid,
marks,
ROW_NUMBER() OVER (PARTITION BY sid
ORDER BY marks DESC) maxmarks
FROM results) r
JOIN students st
ON r.id = st.id
JOIN subjects sj
ON r.sid = sj.sid
WHERE r.maxmarks = 1
you can simple add the new join, and i suggest you the use of explicit join sintax
SELECT t.name, s.sname AS SubjectName, MAX(r.marks) AS MaxMarks
FROM subjects s
INNER JOIN results r ON s.sid=r.sid
INNER JOIN Students t ON t.id = r.id
GROUP BY r.sid, s.sname, t.name
ORDER BY r.sid
In the implicit join sintax should be
SELECT s.sname AS SubjectName, MAX(r.marks) AS MaxMarks
FROM subjects s, results r, stundet t
WHERE s.sid=r.sid
and t.id = r.id
GROUP BY r.sid, s.sname, t.name
ORDER BY r.sid

select max for more than one column?

Suppose i have the following table
Students (StudentID, StudentName)
StudentMarks (StudentID, Mark)
I need to select the student with the highest mark.. if there is more than one student have the same mark (and its the highest mark).. then select according to name order (alphabatically)
How can i do this? Thanks in advance
I haven't tested this, but it sounds right
SELECT StudentID, StudentName
FROM Students
JOIN StudentMarks USING (StudentID)
WHERE Mark =
(SELECT MAX(Mark) FROM StudentMarks)
ORDER BY StudentName
SELECT s.StudentName, sm.Mark
FROM Students s
INNER JOIN StudentMarks sm ON sm.StudentID = s.StudentID
WHERE sm.Mark = (SELECT MAX(Mark) FROM StudentMarks)
ORDER BY s.StudentName
how about
select *
from students s
inner join studentmarks m on m.studentid = s.studentid
where m.mark = (select Max(mark) from studentmarks)
order by s.StudentName
Other options
SELECT * FROM Students where StudentId in (SELECT StudentID FROM Mark Where Mark = Max(Max));
or
SELECT s.* FROM Students where exists (SELECT StudentID FROM Mark m Where Mark = Max(Max) and m.StudentId = s.StudentId);
This just needs a simple join and to select the first record.. (by pre-ordering them according to specs)
SELECT TOP 1
S.StudentName, SM.Mark
FROM
Students S
INNER JOIN StudentMarks SM ON SM.studentID = S.StudentID
ORDER BY
SM.Mark DESC,
S.StudentName ASC
If your RDBMS supports analytic functions
WITH Ranked AS
(
SELECT RANK() OVER(ORDER BY Mark DESC) AS Rnk,
Students.StudentID,
Students.StudentName,
Mark
FROM Students
JOIN StudentMarks ON Students.StudentID = StudentMarks.StudentID
)
SELECT StudentID,
StudentName,
Mark
FROM Ranked
WHERE Rnk=1
ORDER BY StudentName
Or for the other interpretation of the spec...
WITH RowNumbered AS
(
SELECT ROW_NUMBER() OVER(ORDER BY Mark DESC, StudentName ASC) AS Num,
Students.StudentID,
Students.StudentName,
Mark
FROM Students
JOIN StudentMarks ON Students.StudentID = StudentMarks.StudentID
)
SELECT StudentID,
StudentName,
Mark
FROM RowNumbered
WHERE Num=1
How about...
SELECT *
FROM Students
WHERE StudentID IN (SELECT StudentID
FROM StudentMarks
WHERE Mark = (SELECT MAX(Mark)
FROM StudentMarks))
ORDER BY StudentName
LIMIT 1;
(expanding on Vash's answer to remove the nonstandard features from it).