writing subquery in the where clause - sql

I have the following tables
student(student_id, name)
assignment(student_id, course_code, assignment number)
I'm trying to write a query to return those students who have submitted assignment number 1 for a particular course but not assignment number 2
I've written the following query but struggling to itso it returns results on per course basis. Any suggestions?
SELECT name, a.student_id, course_code
FROM assignment a INNER JOIN student s
on a.student_id = s.student_id
WHERE assignment_number = 1
AND assignment_number != 2

SELECT name, a.student_id, course_code
FROM assignment a INNER JOIN student s
on a.student_id = s.student_id
WHERE assignment_number = 1
AND not exists (select * from
assignment a2 inner join student s2
where a2.student_id = s2.student_id
and s2.student_id = s.student_id
and a2.assignment_number = 2)
Here's the fiddle to see it in action:
http://sqlfiddle.com/#!2/48997/2

SELECT
s.name,
s.student_id,
a.course_code
FROM
assignment a
INNER JOIN
student s
ON
a.student_id = s.student_id
WHERE
assignment_number in( 1,2 )
GROUP BY
s.name,
s.student_id,
a.course_code
HAVING max(assignment_number) = 1

List of students that have completed assignment 1, but not completed assignment 2:
select s.name, a.student_id, a.course_code
from assignment a
inner join student s on a.student_id = s.student_id
where a.student_id in
(Select student_id from assignment
where assignment_id = 1) -- All students that submitted Assignment 1
and a.assignment_id !=2

Related

Write a query to display the student names and the maximum mark scored by them in any subject

I have tried using group by and getting an error message of single row function cannot return multiple values.
It has three tables to be selected student, subject and mark.
If you only required student_id and MAX number, you can use only tables Student and Marks as below-
SELECT A.stident_id,MAX(B.Value) max_marks
FROM Student A
INNER JOIN Mark B ON A.Student_id = B.Student_id
GROUP BY A.stident_id
But if you need subject name as well, you can try this below logic-
SELECT AA.stident_id,AA.stident_name,
D.Subject_name,AA.max_marks
FROM
(
SELECT A.stident_id,A.stident_name,MAX(B.Value) max_marks
FROM Student A
INNER JOIN Mark B ON A.Student_id = B.Student_id
GROUP BY A.stident_id
)AA
INNER JOIN Marks C ON AA.stident_id = C.stident_id
AND AA.max_marks = C.Value
INNER JOIN Subject D ON C.subject_id = D.subject_id

SQL MAX() grouping

Tables:
student(sid, sname, sex, age, year, gpa)
major(dname, sid)
Question:
For each department with more than 15 students majoring in the department, we want to print information about the student(s) with the highest GPA within the department. In particular, for each such student, we want to print the student id, student name and GPA, and the department name the student is major in.
So far I have:
SELECT student.sid, student.sname, student.gpa, major.dname
FROM student
RIGHT JOIN major ON student.sid = major.sid
WHERE student.gpa IN (
SELECT MAX(gpa)
FROM student JOIN major ON student.sid = major.sid
GROUP BY dname
HAVING COUNT(dname) > 15
)
But it doesn't give me the accurate query. The clause inside the IN works but when put together in this way it doesn't actually match student.gpa to dname max GPA. What am I doing wrong here?
This Query gives:
enter image description here
I need:
enter image description here
Your inner query gives you the maximum GPA for each department. Then the outer query returns all students who have a GPA equal to any of the maximum GPA's, regardless of the department. The quickest fix of your code is to use a correlated subquery, that will find the maximum GPA for the student's specific department.
SELECT s.sid, s.sname, s.gpa, sm.dname
FROM student s
RIGHT JOIN major sm ON s.sid = sm.sid
WHERE student.gpa IN (
SELECT MAX(ds.gpa)
FROM student ds JOIN major dm ON ds.sid=dm.sid
WHERE dm.dname = sm.dname
GROUP BY dm.dname
HAVING COUNT(dm.dname)>15
)
This query:
select dname, max(s.gpa) maxgpa
from major m inner join student s
on s.sid = m.sid
group by dname
having count(s.sid) > 15
returns all the departments with more than 15 students and the highest gpa in that department.
Join it to the 2 tables like this:
select s.sid, s.sname, s.gpa, t.dname
from (
select dname, max(s.gpa) maxgpa
from major m inner join student s
on s.sid = m.sid
group by dname
having count(s.sid) > 15
) t
inner join major m on m.dname = t.dname
inner join student s on s.sid = m.sid and s.gpa = t.maxgpa
Or with window functions:
select t.sid, t.sname, t.gpa, t.dname
from (
select m.dname, s.*,
rank() over (partition by m.dname order by s.gpa desc) rn,
count(s.sid) over (partition by m.dname) counter
from major m inner join student s
on s.sid = m.sid
) t
where t.counter > 15 and t.rn = 1
If you change your WHERE ... IN statement to be an INNER JOIN, you can connect more fields.
SELECT student.sid, student.sname, student.gpa, major.dname
FROM student
RIGHT JOIN major
ON student.sid = major.sid
INNER JOIN (
SELECT MAX(gpa) as max_gpa, dname
FROM student JOIN major ON student.sid=major.sid
GROUP BY dname
HAVING COUNT(dname)>15
) as dept_gpa
ON student.gpa = dept_gpa.max_gpa
AND major.dname = dept_gpa.dname

Selecting exact value in SQL

I am stuck on a query and decided to ask for help here.
I have 2 tables Students and Values. In students I have the Name and in Values I have the grade.
Let's suppose we have 3 students.
**X** 7,8,10
**Y** 6,9,7
**Z** 7
How can i select the students with the grade EXACTLY "7"?
I tried:
SELECT WHERE grade = 7 But it takes in the consideration the students who have "7" but also other grades too.
I think this problem is tricky, can someone give a hint?
One way is to use a comparison between unconditional and conditional counts:
select s.student_name
from students s join grades g on s.student_id = g.student_id
group by student_id
having count(*) = count(case when g.value = 7 then 1 end)
;
(guessing at some column names along the way)
How it works: After joining the two tables, the rows are grouped by student_id. Then COUNT(*) counts all the grades, and the conditional count counts the grades equal to 7. The query returns the student names when the two counts are equal (meaning all the grades are 7).
Another solution (less efficient):
select s.student_name
from students s inner join grades g on s.student_id = g.student_id
where g.grade = 7
minus
select s.student_name
from students s inner join grades g on s.student_id = g.student_id
where g.grade != 7 or g.grade is null
;
One simple way is to look at the task like this: Find students that have no grade other than seven.
select *
from students
where not exist
(
select *
from grades
where grades.student_id = students.student_id
and grades.grade <> 7
);
or
select *
from students
where student_id not in
(
select student_id
from grades
where grade <> 7
);
I think that an INNER JOIN followed by an exclusive LEFT JOIN would do the trick. Something like this:
WITH
seven AS (
SELECT a.id, a.name, b.grade
FROM student_name a
INNER JOIN student_grade b
ON a.id = b.id
WHERE b.grade = '7'
)
, not_seven AS (
SELECT a.id, a.name, a.grade
FROM seven a
LEFT JOIN student_grade
ON a.id = b.id
WHERE b.id IS NULL
AND b.grade <> '7'
)
SELECT * FROM not_seven;
what about using count and sum? Would that work?
select s.student, Count(v.grade), sum(v.grade)
From student as s
join values as v on v.student = s.student
group by student
having sum(v.grade) = 7 and count(v.grade) = 1

SQL not group by expression, Find student who has taken at least 5 courses

select s.name, s.id
from student s join takes t on t.id = s.id
where s.name like 'D%'
group by s.name, s.id
having (
select count(distinct c.course_id)
from course c
where c.dept_name = 'History' and c.course_id = t.course_id)>4
order by s.name
I am confused about how GROUP BY works. I am trying to find the students who has taken at least 5 courses from history department and name start with D.
Not sure with the nested subqueries...
course(course id, title, dept name, credits)
student(ID, name, dept name, tot_cred)
takes(ID, course_id, sec_id, semester, year, grade)
You have to additionally JOIN with course table:
select s.name, s.id
from student s
inner join takes t on t.id = s.id
inner join course c on c.course_id = t.course_id
where s.name like 'D%' and c.dept_name = 'History'
group by s.name, s.id
having count(distinct c.course_id) >= 5
The WHERE clause returns all students whose names start with a 'D' and have taken at least one course in history department. The HAVING clause filters out any students with 4 or less distinct courses in history department.

How to count students and classes of every teacher in SQL Server?

Assume 3 tables like this:
Teacher:
teacher_id, name, ...
Student:
student_id, teacher_id, ...
Class:
class_id, teacher_id, ...
Is there a SQL query to get how many students and classes are assigned to every teacher?
Result should be something like this:
teacher_id name students classes
t_001 AAA 3 2
t_002 BBB 1 2
...
Try something like this:
SELECT
t.teacher_id, t.name,
Classes = (SELECT COUNT(*) FROM Class c WHERE c.teacher_id = t.teacher_id),
Students = (SELECT COUNT(*) FROM Student s WHERE s.teacher_id = t.teacher_id)
FROM teacher t
with teacher_students as (
select t.teacher_id,
t.name,
count(s.student_id) as students
from Teacher t
left outer join Student s
on t.teacher_id = s.teacher_id
group by t.teacher_id, t.name
),
teacher_classes as (
select t.teacher_id,
count(c.class_id) as classes
from Teacher t
left outer join Class c
on t.teacher_id = c.teacher_id
group by t.teacher_id
)
select ts.teacher_id,
ts.name,
ts.students,
tc.classes
from teacher_students ts
join teacher_classes tc
on ts.teacher_id = tc.teacher_id
try this:
SELECT T.TEACHER_ID
, T.NAME,
, COUNT(C.TEACHER_ID ) AS CLASSES
, COUNT(S.TEACHER_ID ) AS STUDENTS
FROM TEACHER T
LEFT OUTER JOIN CLASS C
ON T.TEACHER_ID = C.TEACHER_ID
LEFT OUTER JOIN STUDENT S
ON T.TEACHER_ID = S.TEACHER_ID
GROUP BY T.TEACHER_ID, T.NAME