SQL - Not sure if I should use joins to resolve this query - sql

I have the following question presented to me:
"Write a SQL command to display for each student who has an average result of greater than 60, the student’s name, the total number of attempts the student has had at all exams, and the student’s average result."
The tables I am working with for this are:
Mark, with fields examID(PK), studentID(PK), result, occurred, noOfAttempts
And Student with the fields id(PK) and Name.
The field StudentID in mark is also a foreign key to Student.
Anyways this is what I've come up with so far:
SELECT S.name, AVG(M.RESULT) FROM STUDENT S, MARK M
WHERE S.ID = (
SELECT studentID FROM
MARK
WHERE 60 <
(SELECT AVG(result) from MARK));
But it is igiving me a "not a single group function" error. I've tried using some other joins but that also resulted in a whole ton of errors so I'm pretty sure I did those wrong.
At this point I am nearly completely lost. I know that the "deepest" subquery will return me the student ID's that have an average result bigger than 60, but when I try to return all student ID's that match that particular ID it doesnt work. I'm also not sure how to count the total no. of attempts in this query so I didnt even attempt that for now.
Table data:

You can try something like that:
SELECT
S.name, SUM(M.noOfAttempts) AS attempts, AVG(M.RESULT) AS result
FROM
STUDENT S
INNER JOIN
MARK M ON (S.ID = M.studentID)
GROUP BY
S.ID, S.name
HAVING
AVG(M.RESULT) > 60

Related

Average grade of student temporary table in SQL Server

I have a database with the following tables:
Students_T (SNo, SDedc, SAddress)
Courses_T (CNo, CDesc)
CoursesRegister_T (CRNo, CR_CNo, CR_SNo, CRGrade)
I need to represent the following data:
For each student show:
Student desc, Course desc, Course grade, Grades average
And I need to do this for every course that the student register in.
For example:
if student A is registered to course B and his grade is 90
and he's also registered to course C and his grade is 70, I suppose to get the following table:
A B 90 80
A C 70 80
The important thing is that I need to use temporary tables with SELECT INTO syntax and I can't figure it out.
I'm using SQL Server.
Someone know how to do that?
EDIT:
I already did this:
select CR_ST_No, ST_Desc, CR_Desc, CR_Grade
into #Grades
from Students_T
left join CoursesRegister_T on CR_ST_NO = ST_No
where CRS_Desc is not null
select *
from #Grades
drop table #Grades
and it's giving me table with all data I need except the average.
When I try to change the row select * to select *, avg(CR_Grade)
it can't execute.
This is a typical use case for a Window Function. You haven't provided any sample data and I can't test it right now, but something like that should work:
SELECT s.SDedc, c.CDesc, r.CRGrade, AVG(r.CRGrade) OVER (PARTITION BY s.SNo) AS average_grade
FROM Students_T AS s
LEFT JOIN CoursesRegister_T AS r ON r.CR_SNo = s.SNo
LEFT JOIN Courses_T AS c ON r.CR_CNo = c.CNo;
From your question and the subsequent comments, you need to change your select-statement to include a group by clause.
Please read through the MSDN SELECT (Transact-SQL) article as to how a select statement is structure, with explanations and examples of each section.
The reason you are getting your error message is that the AVG is an aggregate function and so requires that all columns that are not part of the aggregate, to be included into the group by clause of your select statement.

why results of two queries are different?

select distinct ID, title, takes.course_id
from course join takes
on course.course_id = takes.course_id
where takes.course_id in
(select takes.course_id
from takes
where ID = '10204');
select ID, title, takes.course_id
from course join takes
on course.course_id = takes.course_id
where ID = '10204';
I want to query the course IDs and the titles of the courses that a student whose ID is 10204 takes. The first gives a result with 5000 rows which is incorrect. The second give a correct result. So what is wrong with the first?
The first query gives you data for all students that happen to take a course that 10204 also takes.
Essentially the first query can be read as "Find all courses and the students that take them, for any course that is also taken by student 10204". You can look at the first query as a 3 way join. The results of the subquery select takes.course_id from takes where ID = '10204' would be the "third" table.
Adding to the pile on since everyone seems to be offering bits and pieces, some of which are oddly irate...
The first query says "Give me information on the students and courses where the courses were also taken by student 10204"
The second query says "Give me information on the students and courses taken by student 10204"
You say you wanted to get the course IDs and Titles for the courses taken by the student 10204, so obviously the second query is the correct one. You don't care about other student's that have taken the same courses.
Perhaps, to put it into perspective, rewriting the first, and incorrect query will help:
select distinct ID, title, takes.course_id
from course
join takes
on course.course_id = takes.course_id
join takes as takes2
on takes.course_id = takes2.course_id
WHERE
takes2.ID = '10204');
Well that is could be because in the first query you are quering where the course_id in takes table is equal to a specific course_id in that table (WHICH CAN BE NOT UNIQUE)
and in the second query you are straightly querying where the course_id is equal to a unique ID in that table!
Thanks you guys. I think my problem is that I did not realize that other students can take the same courses with the student having ID 10204. That this why though the condition is to query only courses take by the students 10204, the results is all about the courses taken by both 10204 and other students.
Because takes.ID != course.ID. The first you use takes.ID in the where clause but the second you use course.ID

SQL query to return only students with specific score on all tests

Have a table for student test scores.
Students take multiple quizzes during a period.
Trying to develop a query that will pull only the students with 100% on all of the quizzes.
Table - Students
StudentId,
QuizScore
Certainly a student could receive 100% on a quiz or multiple quizzes, but just a list of the students whom scored 100% on all quizzes.
Thinking of a nested query but drawing a blank :(
Thanks in advance
Select studentid
From studentscores
Group by studentid
Having avg(quizscore) = 100
You can do an inner select to find students with at least one score that isn't 100, and then select all the StudentIDs that aren't in that set.
SELECT Distinct StudentID FROM Students WHERE StudentID NOT IN
(SELECT StudentID FROM Students WHERE QuizScore != 100)
You also want to use Distinct to get rid of multiple lines.
There are several ways to do this, one is to compare the count of all the results to those with 100. You can use case with count for that:
select studentid
from students
group by studentid
having count(case when quizscore >= 100 then 1 end) = count(*)
If quizes could have higher than 100, I've changed = to >= in the case statement to account for those. Otherwise, go with #Rajesh's solution as I believe it's the easiest to check for all 100s.

Access flag record when match found in table 2 (one-to-many relationship)

I have an educational db with a tbl_Students and tblStudentPrograms. The tblStudentPrograms has one record per student and program (ProgramID) per year (YearID.
I need to find out how many students participated in ProgramID=2 EVER. So, I need the DISTINCT subset of students who have participated in the program for any YearID.
(Of course, this will be complicated further by trying to find other records in other tables such as StudentAdvising as well , but this will be a good start.)
Thank you!
SELECT DISTINCT count(studentID) FROM tblStudentPrograms WHERE ProgramID = 2
Assuming you want a distinct count of students (excluding those where the same student may have taken a program twice...
SELECT count(distinct StudentID)
FROM tblStudentPRograms
WHERE ProgramID = 2
Assuming you want a distinct count of students (excluding those where the same student may have taken a program twice...
SELECT count(distinct StudentID)
FROM tblStudentPRograms
WHERE ProgramID = 2
though I'm not positive access supports a distinct w/in a count like other RDBMS do...
so you may have to do:
SQL : how can i count distinct record in MS ACCESS
SELECT count(BStudentID) as DistinctStudentsInProgram
FROM (select distinct studentID, ProgramID from tblStudentPrograms) B
WHERE B.ProgramID = 2

SQL Server query to know if an id in a column equals to other in another column

I’ve been hours trying to build this query and I need your help so I can make it.
This is table Students (made out of inner joins):
SpecialtyChosenID StudentID Subject SubjectSpecialtyID
5ABFB416-8137 15 Math A1EBF3CB-E899
5ABFB416-8137 15 English A1EBF3CB-E899
The info in it means that a student with id no. 15 has chosen an specialty with id 5ABFB416-8137
The two subjects he has passed (Math and English) belong to a specialty with id A1EBF3CB-E899
What would be the query to know if the passed subjects belong to the specialty chosen by the student??
Counting the number of subjects with the same SubjectSpecialtyID as SpecialtyChosenID and vice versa could do.
Thanks a lot
You can do a self join. This finds the number of subjects taken by the student that match the student's chosen specialities.
SELECT l.SpecialtyChosenID, l.StudentID, Count(Distinct r.Subject) FROM Students l
LEFT JOIN Students r ON (l.StudentID=r.StudentID AND l.SpecialityChosenID=r.SubjectSpecialityID)
GROUP BY l.SpecialtyChosenID, l.StudentID
However, this is quite inefficient using the table structure given. If you have a table listing students with their specialities, and another with subjects and specialities, and a third relating students with subjects, it would be better to build this query from the base data, rather than from the derived data.
SELECT * FROM Students WHERE SpecialtyChosenID = SubjectSpecialtyID
If you only need the list of matching subjects and you have the SpecialtyChosenID you can do something like
SELECT * FROM Students
WHERE SubjectSpecialtyID = SpecialityChosenID
CASE WHEN SpecialtyChosenID = SubjectSpecialtyID THEN 1 ELSE 0 END AS specialty