Say we have two entities:teacher and student.
each teacher has multiple student.
Now I want to:
query for at most 5 teachers,and for each teacher, no more than 10 of his student.
So far this can be done quite easily by:
select *,
(
select GROUP_CONCAT('<sid>',students.name,'</sid>') from students on
teachers.id=students.teacher limit 10
) as students
from teachers limit 5
But that's not the whole story yet.
AND
If anyone of the teachers has more than 10 students,should return true for that teacher,otherwise false
How to do this in SQL?
Pseudo SQL: one row of results for each of the 10 students for each of the 5 teachers
select t.teacher_id, s.student_id,
case when t2.count > 10 then 'true' else 'false' end
from
(select top 5 *
from teachers
order by teacher_id) t
join
(select top 10 *
from students s1 join teachers t1 on s1.teacher_id = t1.teacher_id
order by student_id) s
on t.teacher_id = s.teacher_id
join
(select teacher_id, count(*) as count
from teachers t join students s on t.teacher_id = s.teacher_id
group by teacher_id) t2
on t2.teacher_id = t.teacher_id
LINQ makes this super-easy
Use a subquery for every teacher selected.
Related
The students table has 4 fields. Student ID, name, location, and mentor ID. The mentor ID points to a student ID. Students can mentor many people, however a person can only have one mentor.
The two methods I have come up with are as follows:
SELECT s.Name
FROM Students s
WHERE s.Id IN (SELECT s2.MentorId
FROM Students s2
GROUP BY s2.MentorId
HAVING COUNT(s2.MentorId) > 4)
OR
SELECT s2.Name
FROM students s
JOIN students s2 ON s2.Id = s.MentorId
GROUP BY s2.Name
HAVING COUNT(s2.Name) > 4
Are these correct? They do not run for me. I am unsure if this is an error with my SQL or my code.
Thanks!
No, they are not correct, but it's only a small, simple mistake. (same mistake in both).
You are counting the wrong column in the having clause.
Personally, I would go with the second option, only replace the COUNT(s2.Name) to COUNT(s.Id) - and if your database supports it, COUNT(DISTINCT s.Id) is even better:
SELECT s2.Name
FROM students s
JOIN students s2
ON s2.Id = s.MentorId
GROUP BY s2.Name
HAVING COUNT(DISTINCT s.Id) > 4
I would start with aggregation. The students who are mentoring more than 4 students are given by:
select s.mentorid
from students s
group by s.mentorid
having count(*) > 4;
To get the full student record, you can then use in, exists, or join:
select s.* -- or whatever columns you like
from students s join
(select s.mentorid
from students s
group by s.mentorid
having count(*) > 4
) m
on s.id = m.mentorid;
You were grouping by s2.name having a number of s2.name greater than 4. You never use the same field for grouping and the aggregate function. What you really want here is grouping by s2.name having a number of s.name (you want to count the corresponding students for each mentor mentor : GROUP BY mentor HAVING COUNT students > 4)
You should infact use s.id because otherwise it will not work if you have several students with the same name
SELECT s2.Name
FROM students s
JOIN students s2 ON s2.Id = s.MentorId
GROUP BY s2.Name
HAVING COUNT(s.id) > 4
Tested and it works :)
My end goal is to create a list of honor roll students. Each student has multiple rows, one for each grade. I want to say, look at their grades across these rows; only show 1 student name if none of their grades are <80%.
I've started just with this, but I'm stuck, I don't know how to assess across the multiple rows as a criterion for selecting a unique list.
SELECT students.first_name, students.last_name, storedgrades.storecode, storedgrades.percent,storedgrades.course_name
FROM storedgrades join
students
on students.ID = storedgrades.StudentID
where students.enroll_status=0 AND
storedgrades.termid>2799 AND
storedgrades.storecode = 'Q4'
Example of grades table:
BOB A 95
BOB D 65
ANDREA B 85
ANDREA A 95
EXAMPLE RESULT:
ANDREA
Use aggregation. I think this is what you want:
select s.id, s.first_name, s.last_name
from students s join
storedgrades sg
on s.ID = sg.StudentID
where s.enroll_status = 0 and
sg.termid > 2799 AND
sg.storecode = 'Q4'
group by s.id, s.first_name, s.last_name
having count(*) = 5 and -- you want all five courses
min(scorecode) >= 80;
Select a distinct list of student names, then compare with a NOT EXISTS to the grades table where the grade is less than 80%
SELECT distinct students.ID, students.first_name, students.last_name
FROM storedgrades s join
students
on students.ID = storedgrades.StudentID
where students.enroll_status=0 AND
storedgrades.termid>2799 AND
storedgrades.storecode = 'Q4' and not exists
(select 'x' from storedgrades s2 where s2.students.StudentID = s.StudentID and s2.first_name = s.first_name and
s.last_name = s2.last_name and s2.percent < 80)
EDIT: added in studentID to the join
I'm trying to write sql query which return me subject_id(result table) where primary_skill(student table) is unique.
Result table has column (student_id, subject_id, mark)
My query:
SELECT r.subject_id
FROM result r
JOIN student s ON r.student_id = s.student_id
WHERE s.primary_skill IN (SELECT DISTINCT primary_skill
FROM student)
GROUP BY 1;
I have this result:
subject_id
1
2
3
4
5
6
7
8
9
10
1001
But I should return only id 1001, because only this subject has unique student primary_skill, in other ids primary skill are repeated.
What am I doing wrong? How it improve?
Please try following:
select result.subject_id from student
join result on student.id =result.student_id where
student.primary_skill in
(select primary_skill from student group by primary_skill having COUNT(*)=1)
If I understand this right, you want results for students only having one skill. You can use GROUP BY and a HAVING clause checking for the count of skill being equal to one for this.
SELECT r.subject_id
FROM result r
INNER JOIN (SELECT s.student_id
FROM student s
GROUP BY s.student_id
HAVING count(DISTINCT s.primary_skill) = 1) x
ON x.student_id = r.student_id;
I have two tables, student and school.
student
stid | stname | schid | status
school
schid | schname
Status can be many things for temporary students, but NULL for permanent students.
How do I list names of schools which has no temporary students?
Using Conditional Aggregate you can count the number of permanent student in each school.
If total count of a school is same as the conditional count of a school then the school does not have any temporary students.
Using JOIN
SELECT sc.schid,
sc.schname
FROM student s
JOIN school sc
ON s.schid = sc.schid
GROUP BY sc.schid,
sc.schname
HAVING( CASE WHEN status IS NULL THEN 1 END ) = Count(*)
Another way using EXISTS
SELECT sc.schid,
sc.schname
FROM school sc
WHERE EXISTS (SELECT 1
FROM student s
WHERE s.schid = sc.schid
HAVING( CASE WHEN status IS NULL THEN 1 END ) = Count(*))
You can use not exists to only select schools that do not have temporary students:
select * from school s
where not exists (
select 1 from student s2
where s2.schid = s.schid
and s2.status is not null
)
You can use a regular join.
SELECT DISTINCT c.schName
FROM Students s
INNER JOIN Schools c ON s.schid = c.schid
WHERE s.status IS NULL
I'm trying to make a query that looks at a single table to see if a student is in a team called CMHT and in a medic team - if they are I don't want to see the result.
I only want see the record if they're only in CMHT or medic, not both.
Would the right direction be using sub query to filter it out? I've done a search on NOT IN but how could you get to see check if its in more then 2 teams are not?
Student Team ref
1 CMHT 1
1 Medic 2
2 Medic 3 this would be in the result
3 CMHT 5 this would be in the result
So far I've done the following code would I need use a sub query or do a self join and filter it that way?
SELECT Table1.Student, Table1.Team, Table1.refnumber
FROM Table1
WHERE (((Table1.Team) In ('Medics','CMHT'))
This is Mark Byers's answer with a HAVING clause instead of a subquery:
SELECT Student, Team, ref
FROM Table1
GROUP BY Student
HAVING COUNT(Student) = 1
SELECT *
FROM students
WHERE NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'CMHT'
)
OR NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'Medic'
)
SELECT a.*
FROM Table1 a
INNER JOIN
( SELECT Student, COUNT(*) FROM Table1
GROUP BY Student
HAVING COUNT(*) = 1)b
ON (a.Student = b.Student)
how could you get to see check if its in 2 or more teams?
You can count the number of teams per student and then filter only those you want to see:
SELECT student FROM
(
SELECT student, COUNT(*) AS cnt
FROM Table1
GROUP BY student
) T1
WHERE cnt = 1
You can do it with outer join
select COALESCE(t1.Student, t2.Student) as Student,
COALESCE(t1.Team, t2.Team) as Team,
COALESCE(t1.ref, t2.ref) as ref
from
(select * from Student where Team = 'CMHT') t1
outer join
(select * from Student where Team = 'Medic') t2
on t1.Student = t2.Student
where
t1.Student is null or
t2.Student is null;