select top 3 from table - sql

I have three tables.
Table 1:
Student
----------
studentID
StudentName
Table 2:
Studentmarks
----------------
studentID
subjectId
marks
Table 3:
Subject
---------
subjectID
subjectName
I need a query to get top 3 students in each subject.
I want output like:
----------------------------------------------------------------
StudentID Name subjectId subjectName marks
-----------------------------------------------------------------
1 AAA 1 phy 85
2 BBB 1 phy 75
3 CCC 1 phy 65
3 CCC 2 bio 85
4 DDD 2 bio 75
1 AAA 2 bio 65
6 FFF 3 che 85
1 AAA 3 che 75
5 EEE 3 che 65
3 CCC 4 mat 85
2 BBB 4 mat 75
4 DDD 4 mat 65

WITH CTE
AS
(
SELECT
s.StudentID,
s.StudentName,
sm.subjectId,
j.SubjectName,
sm.marks,
ROW_NUMBER() OVER(PARTITION BY sm.subjectId
ORDER BY sm.marks DESC) AS RN
FROM student AS s
INNER JOIN Studentmarks AS sm ON s.studentID = sm.studentID
INNER JOIN Subject AS j ON sm.subjectId = j.SubjectId
)
SELECT
StudentID,
StudentName,
subjectId,
SubjecTName,
marks
FROM CTE
WHERE RN <= 1;

Related

sql join gives cumulative results

I want to join county and county_type tables and get only those county that doesnt have a type =30. From below example id = 1 and 3 should only be the expected output
county
id name zipcode
1 LC 12345
2 WC 98765
3 AC 09876
4 VC 90876
county_type
id type
1 10
1 20
2 10
2 20
2 30
3 10
3 20
4 10
4 20
4 30
output:
id name zipcode
1 LC 12345
3 AC 09876
Tried this:
select *.c from county c, county_type ct
where c.id = ct.id
and ct.id != 30
order by c.id asc;
what i am getting is cumulative:
id name zipcode
1 LC 12345
1 LC 12345
2 WC 98765
2 WC 98765........///
You want not exists:
select c.*
from county c
where not exists (select 1
from county_type ct
where ct.id = c.id and ct.type = 30
);

SQL query to find out the single record by 3 conditions

Can you please help me with the query to find out the single record for the each student based on the subject.(Id,Name,subs are primary key). Ideally I will have 2 records for each subject. One with school TTT and MCC.
Table Structure:
StudentID StudentName Subject Marks School
1 AAA ENG 80 TTT
1 AAA ENG 80 MCC
1 AAA TAM 90 TTT
1 AAA TAM 90 MCC
2 BBB TAM 90 TTT
2 BBB TAM 90 MCC
3 CCC ENG 40 MCC
4 DDD ENG 95 MCC
5 EEE ENG 85 TTT
5 EEE ENG 85 MCC
I want the results
StudentID StudentName Subject Marks School
3 CCC ENG 40 MCC
4 DDD ENG 95 MCC
Here is one method using window functions:
select t.*
from (select t.*,
count(*) over (partition by studentid) as cnt
from t
) t
where cnt = 1;
This returns students with only one record. If you want student/subject combination with only one record, another method uses not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.studentid = t.studentid and
t2.subject = t.subject and
t2.school <> t.school
);
SELECT * FROM TABLEA A
WHERE EXISTS (SELECT STUDENTid, COUNT(1) TOTAL FROM TABLEA B
WHERE A.STUDENTID = B.STUDENTID
GROUP BY STUDENTID
HAVING COUNT(1) = 1)
This will give records to cases where there is no duplication of IDs
You can filter with a correlated subquery:
select t.*
from mytable t
where (select count(*) from mytable t1 where t1.studentid = t.studentid) = 1

How to build query? Any idea?

3 tables:
Mark table:
student_id sa_id marks
1 1 75
1 2 80
1 3 100
2 4 85
2 5 90
2 6 60
course table:
course_code sat_id name_code
AAA 100 1 midterm1
AAA 100 2 midterm2
AAA 100 3 final
BBB 200 4 midterm1
BBB 200 5 midterm2
BBB 200 6 final
transform table:
sa_id sat_id
1 1
2 2
3 3
4 4
5 5
6 6
select course.course_code, mark.marks
from mark
left outer join transform on transform.sa_id = mark.sa_id
left outer join course on course.sat_id = transfrom.sat_id
where course.name_code = 'midterm1'
At the above query only midterm1 result, also we can extract mid2 and final
select mark.student_id,course.course_code, mark.marks, course.name_code
from mark
left outer join transform on transform.sa_id = mark.sa_id
left outer join course on course.sat_id = transfrom.sat_id
order by mark.student_id, course.course_code
Result will give:
student_id course_code marks name_code
1 AAA 100 75 midterm1
1 AAA 100 80 midterm2
1 AAA 100 100 final
2 BBB 200 85 midterm1
2 BBB 200 90 midterm2
2 BBB 200 60 final
So how to build query that should be
student_id course_code midterm1 midterm2 final
1 AAA 100 75 80 100
2 BBB 200 85 90 60
You can use case when , group by (and a fake aggregation function)
select
student_id
, course_code
, max(case when name_code ='midterm1' then mark else null) midterm1
, max(case when name_code ='midterm2' then mark else null) midterm2
, max(case when name_code ='final' then mark else null) final
from mark
left outer join transform on transform.sa_id = mark.sa_id
left outer join course on course.sat_id = transfrom.sat_id
group by student_id, course_code
order by mark.student_id, course.course_code
But if you don't like aggregation functio you can use a 3 seleft join on mark
select
mm1.student_id
, mm1.course_code
, mm1.mark midterm1
, mm2.mark midterm2
, mm3.mark finale
from mark as mm1
left join mark as mm2 on mm1.student_id = mm2.student_id and mm1.course_code = mm2.course_code
left join mark as mm3 on mm1.student_id = mm3.student_id and mm1.course_code = mm3.course_code
left outer join transform on transform.sa_id = mm1.sa_id
left outer join course on course.sat_id = transfrom.sat_id
where mm1.name_code = 'midterm1'
and mm2.name_code = 'midterm2'
and mm3.name_code = 'final'

use group by clause and count() in subquery

Table : Class
class_id ClassName
----------------------
1 AAA
2 BBB
3 CCC
Table : Groups
id class_id GroupName
---------------------------
1 1 A1
2 1 A2
3 2 B1
4 3 C1
5 2 B2
6 1 A3
Expected Output :
class_id ClassName count(*)
-------------------------------
1 AAA 3
2 BBB 2
3 CCC 1
Use Inner Join to get result :
SELECT Class.class_id, Class.ClassName, COUNT(*) AS count
FROM Class INNER JOIN
Groups ON Class.class_id = Groups.class_id
GROUP BY Class.class_id, Class.ClassName

Query a table to make each row become 3 rows

I have a table (T1) as follows in SQL server:
id subject student1 student2 student3 score1 score2 score3
1 Maths Peter Leo John 11 12 13
2 Phy Mary May Leo 21 22 23
Is it possible to use a query to make the following result:
id subject name score
1 Maths Peter 11
1 Maths Leo 12
1 Maths John 13
2 Phy Mary 21
2 Phy May 22
2 Phy Leo 23
Although this is an unpivot query, I actually find it easier to do this with explicit logic:
select t1.id, t1.subject,
(case when n.n = 1 then student1
when n.n = 2 then student2
when n.n = 3 then student3
end) as student,
(case when n.n = 1 then score1
when n.n = 2 then score2
when n.n = 3 then score3
end) as score
from t1 cross join
(select 1 as n union all select 2 union all select 3) n;
This should have comparable performance to unpivot. And, it should have better performance than three union all operations (because that requires scanning the table three times).
Assuming the table is called classes, you can union it to itself:
(SELECT student1 as student, subject from Classes)
UNION
(SELECT student2 as student, subject from Classes)
UNION
(SELECT student3 as student, subject from Classes)