Given the following schema, I'm supposed to write queries for the questions.
My first query runs but I get no result and the second one gives the subquery returns more than one row error.
student (sid, sname, sex, birthdate, gpa)
prof (pname, dname)
course (cnum, dname, cname)
section (cnum, secnum, pname)
enroll (sid, cnum, secnum, grade)
For each course, return the number of sections (numsections), total number of students enrolled (numstudents), average grade (avggrade), and number of distinct professors who taught the course (numprofs). Only show courses in Chemistry or Computer Science department. Make sure to show courses even if they have no students. Do not show a course if there are no professors teaching that course.
Return the students who received a higher grade than their course section average in at least two courses. Order by number of courses higher than the average and only show top 5.
Sql query:
SELECT C.cnum, C.cname, COUNT(*) AS numsections, COUNT(E.sid) AS numstudents,
AVG(E.grade) AS avggrade, COUNT(P.pname) AS numprofs
FROM course C
JOIN section S ON C.cnum = S.cnum
JOIN enroll E ON C.cnum = E.cnum
JOIN prof P ON S.pname = P.pname
WHERE C.cname = 'Chemistry' OR C.cname = 'Computer Science'
GROUP BY C.cnum, C.cname;`
SELECT S.sid, S.sname
FROM student S
LEFT JOIN enroll E ON S.sid = E.sid
WHERE E.grade > (SELECT AVG(grade)
FROM course C JOIN enroll E2
ON C.cnum = E2.cnum
GROUP BY C.cnum
LIMIT 5);`
About the second query...
Your subquery is getting more than 1 row of data. To use "<" you need yo be sure you are bringing only 1 row and only 1 column.
And if I understand correctly, you only have to show the top 5 students order by the number of times the are better than the average of the course.. I realice this is a learning example so it wont help if I give you the query..
You need to select the top 5 students, but to know that you have to COUNT() the number of times that their GRADE was greater than the AVG() of each course they have taken, at some point in your subquery you sould have the list of students order by the number of times they achive beeing above the average.
Related
EDIT:
This is the database. The question is:
Find the course title which all the students whom their advisor is professor Katz took that course.
What I thought to solve this question:
1) Find ID of Prof. Katz.
2) Using that ID, find IDs of students whom Prof. Katz advises.
3) Using the founded student IDs, find all courses where Prof. Katz's advisees took.
4) Group the result by student IDs and get the rows present in each group, hence finding the course taken by all advisees of Prof. Katz.
I couldn't perform the step 4.
How to return all rows from a grouped table, where each returned row exists in every group of the table?
SELECT Title
FROM Course INNER JOIN Takes
ON Course.Course_ID = Takes.Course_ID
WHERE Takes.ID IN
(SELECT Student.Id
FROM Student INNER JOIN advisor ON Students.ID = Advisor.s_ID
INNER JOIN instructor ON Advisor.i_ID = Instructor.ID
WHERE Instructor.Name = 'Prof.Katz' )
I couldn't end up retrieving data from multiple tables in a single query.
I have the following tables:
A brief explanation :
A student can study many subjects and subjects can be studied by many students (table Study Created)
A subejct is taught by a lecturer (FK used in (table Subject))
The table Grade gives infos about the marks obtained by a student
The SQL query I was trying to perfom is: Retrieve average students who study subjects taught by lecturer Antonio.
So first I used an AVG aggregation on table grade to get average students:
SELECT Id_Student, Name, AVG(Mark)
AS Average FROM Grade
GROUP BY Id_Student, Name
But my trouble is also to use the result of this SQL query and filter with again with the result of Subjects taught by Lecturer "Antonio".
Is it possible to make it in a one SQL query?
SELECT Id_Student, Name, AVG(Mark) AS Average FROM Grade
where id_student in
(
select student.id_student from subject
join study on subject.id_subject = study.id_subject
join student on study.id_student = student.id_student
where subject.taught_by = L1
)
GROUP BY Id_Student, Name
also you could probably just join GRADE instead of doing the subselect that I did here. But it's hard to tell how it will go without actually testing it.
Using a university relation (students are advised by instructors in different departments, only one advisor per student but advisors can have zero to many advisees), I'm attempting to write a function that computes the total number of students being advised in a given department.
Here are the tables and columns for reference:
student(id,name,dept_name,tot_cred)
instructor(id,name,dept_name, salary)
advisor(s_id,i_id)
I already know how to use delimiter and such so no I don't need to be told how to write a function. I'm just having issues getting what I want from the select statement alone.
This is the best I've been able to come up with so far:
SELECT *
FROM advisor
RIGHT OUTER JOIN instructor
ON i_id=id
ORDER BY dept_name;
This statement yields:
Is there a way I can write an if statement or some other statement to delete all of the NULL entries and then use a count function (within the custom function I'll be writing) that will count the number of instances dept_name occurs, resulting in the total number of advisees per department?
SELECT i.dept_name, COUNT(a.s_id)
FROM Instructor i
LEFT JOIN advisor a ON i.id = a.i_id
GROUP BY i.dept_name;
This will include zeros for departments with no advisees.
If you are interested in the number of advised students per student department then:
SELECT s.dept_name, COUNT(a.s_id)
FROM student s
LEFT JOIN advisor a ON a.s_id=s.id
GROUP BY s.dept_name
OTOH, if you are interested in the number of advised students per instructor department then:
SELECT i.dept_name, COUNT(a.s_id)
FROM instructor i
LEFT JOIN advisor a ON a.i_id=i.id
GROUP BY i.dept_name
It looks like this is what you need:
SELECT i.dept_name, COUNT(a.s_id) FROM instructor i
LEFT OUTER JOIN advisor a ON i.id = a.i_id
GROUP BY i.dept_name;
I have to add that advisor(s_id,i_id) is bad database design if a student really can not have more than 1 advisor as you said. Because in that case, simply add advisor_id to the student relation and get rid of the advisor table.
Also: your use of the word 'function' is incorrect. We are talking about queries here.
Probably you can try this:
SELECT i.dept_name, COUNT(s.*) AS totalAdvisedNum
FROM student s, advisor a, instructor i
WHERE a.s_id = s.id AND a.i_id = i.id GROUP BY i.dept_name
This will select the department name and total number of students being advised by instructors in these departments
If you need to get the number for a specific department you should replace GROUP BY i.dept_name with AND i.dept_name = "name of department"
I have been working on this query for a table lookup for hours and I am finally calling in for help to SO.
There are three tables:
computer (assetTag for ID, other information about a computer)
student (studentID for ID, other student information)
assignment (studentID, assetTag, issueDate)
These are obviously linked as a many to many using assignment like a junction table:
Student <-> assignment <-> computer
I put together a query to show a list of student names, and the last computer assignment they had. The query works great except for one problem I can't wrap my head around. If studentA is assigned computer 10000 and then turns it in, and then that computer is assigned to studentB until the end of the year when they turned it in, looking up that asset shows both students as the rightful owners of the machine. I need it to only show the latest student.
Current query:
SELECT SQL_CALC_FOUND_ROWS s.studentID, s.lName, s.fName, s.uName, s.grade, c.assetTag, c.location, c.`status` FROM student s
INNER JOIN
(
SELECT studentID, MAX(issueDate) MaxDate
FROM assignment GROUP BY studentID
) MaxDates ON s.studentID = MaxDates.studentID AND s.active = 1
INNER JOIN assignment a ON MaxDates.studentID = a.studentID AND MaxDates.MaxDate = a.issueDate AND a.loaner = 0
INNER JOIN computer c ON a.assetTag = c.assetTag
For the most part previous owners of a machine are inactive (s.active = 0) so there aren't very many duplicates but there shouldn't be any duplicate assetTags.
I wish I could aggregate assetTags based off the last assignment EVER.
Any help would be greatly appreciated since I need to get this done pretty fast.
EDIT:
It may help if I explain that there are MANY students to MANY computers and MANY computers to MANY students.
Throughout the year a student may change computers repeatedly and a computer may change to different students repeatedly.
Your subquery could look like this:
SELECT studentID, issueDate MaxDate
FROM assignment
GROUP BY studentID
HAVING issueDate = max(issueDate)
This will return a list of studentIDs with each student's most recent assignment.
As an alternative, you can replace your entire mess of a query with:
select SQL_CALC_FOUND_ROWS s.studentID, s.lName, s.fName, s.uName, s.grade, c.assetTag, c.location, c.`status`, a.issueDate
from assignment a
inner join student s on a.studentID = s.studentID
inner join computer c on a.assetTag = c.assetTag
group by a.assetTag
having a.issueDate = max(a.issueDate)
Updated since having doesn't work like that:
select SQL_CALC_FOUND_ROWS s.studentID, s.lName, s.fName, s.uName, s.grade, c.assetTag, c.location, c.`status`, a.issueDate
from assignment a
inner join student s on a.studentID = s.studentID
inner join computer c on a.assetTag = c.assetTag
where a.issueDate = (select max(issueDate) from assignment where assetTag=a.assetTag)
group by a.assetTag
I have two tables: subject and student.
I'm trying to count the number of subjects enrolled by each student. How do I do that? I'm trying the code below but it doesn't give the answer I need.
SELECT COUNT( subject.SUBJECT ) , student.IDNO, student.FIRSTNAME, subject.SUBJECT
FROM student, subject
GROUP BY subject.SUBJECT
LIMIT 0 , 30
you do have an Enrolment table too, don't you? to resolve the many-to-many relationship between student and subject. you could work with just that. say, your enrolment table has studentID and subjectID columns, then you would only need:
SELECT studentID, COUNT(*) FROM Enrolment GROUP BY studentId;
or, to include their names too,
SELECT s.firstname, COUNT(*) FROM Enrolment e JOIN student s on e.studentId=s.IDNO GROUP BY e.studentId;
You are missing a join condition. Somewhere you are storing info about what subject each student is taking. Perhaps WHERE subject.student_id = student.id.