Three tables courses,registration,students
columns in students
firstname,lastname,studentid,major,admitdate,graddate,gender,dob
columns in registration
courseid,studentid
columns in courses
coursenumber,coursename,credits
select statement I need to modify
select lastname as 'Last Name',sum(credits) as 'Credits Registered For' from students as s
inner join registration as r on s.studentid = r.studentid
inner join courses as c on c.coursenumber = c.courseid
group by last name;
the question on the lab is... Modify the previous query to show all students, even if they have not registered for a class. You should have 14 rows. Students who are not registered will show NULL in output.
I know this requires outer join of some sort but I'm not fully grasping these joins i've read multiple posts on here and other sites but can't seem figure it out.
use LEFT JOIN
select lastname as 'Last Name',
sum(credits) as 'Credits Registered For'
from students as s
LEFT join registration as r on s.studentid = r.studentid
LEFT join courses as c on c.coursenumber = r.courseid
group by last name;
try
SELECT s.lastname AS 'Last Name',
sum(c.credits) AS 'Credits Registered For'
FROM students s
LEFT JOIN registration r ON (s.studentid = r.studentid)
INNER JOIN courses c ON (c.coursenumber = r.courseid)
GROUP BY lastname;
note: no need to use AS while giving alias to table name
Related
i want to write these queries
show the name of students who never Loaned Poetry books.
show the Name of student who Loaned more than 5 books.
show student name, book Title, issue Date, and author name of all bookes issued books.
Query i wrote so far is not working for first task
SELECT
name
FROM
students
INNER JOIN issued ON students.rollno = issued.rollno
GROUP BY
issued.rollno
HAVING
COUNT( issued.rollno )> 2
Give these queries a try
select s.name from students s
left join issued i on (s.rollno = i.rollno)
left join bookcopy bc on (i.copyid = bc.copyid)
left join books b on (bc.bookid = b.bookid)
left join category c on (b.catid = c.catid and c.catname = 'Poetry')
where c.catid is null
select s.name, count(*) as from students s
left join issued i on (s.rollno = i.rollno)
group by s.name
having count(*) > 5
select s.name, b.title, a.authorname, i.issuedate from students s
left join issued i on (s.rollno = i.rollno)
left join bookcopy bc on (i.copyid = bc.copyid)
left join books b on (bc.bookid = b.bookid)
left join author a on (b.authorid = a.authorid);
I have two tables as follows:
==================
StudentsClasses
----------------
ID (Registration ID of the class)
StudentID (ID of student taking class)
ClassID (ID of certain class)
----------------
==================
Students
---------------
ID (ID of student)
Name (Name of student)
GradeLevelID (Grade of student)
---------------
==================
And they are joined by StudentsClasses.StudentID and Students.ID.
I am trying to write a query to return the students with the least classes registered. My query is:
SELECT Students.Name, COUNT(StudentsClasses.StudentID) AS Expr1
FROM StudentsClasses INNER JOIN
Students ON StudentsClasses.StudentID = Students.ID
GROUP BY StudentsClasses.StudentID, Students.Name
ORDER BY Expr1
However, that only returns all the students with at least 1 class in ASC order.
I know the correct answer is 7 students with 0 classes.
How can I modify my query to return only those 7 students with 0 classes.
To enlist those students, that have no classes, instead of INNER JOIN you should be using LEFT JOIN here, to make sure all rows from students table are listed, even though there is no rows in studentclasses for that particular student.
SELECT
s.name, count(sc.id) AS classes
FROM
students s
LEFT JOIN studentsclasses sc ON s.id = sc.studentid
GROUP BY s.name
HAVING count(sc.id) = 0 -- added after comment
ORDER BY count(sc.id);
OR another method (for retrieving only students that have 0 classes):
SELECT
s.name
FROM
students.s
LEFT JOIN studentsclasses sc ON s.id = sc.studentid
WHERE
sc.id IS NULL
This should limit your results to those students having whatever the minimum number of registered classes is (so if the minimum is currently zero, then zero, if it becomes true that the least number of registrations is 3, then it will use 3, etc.)
select s.name,
v.classes
from students s
join (
select s.name,
count(sc.id) as classes
from students s
left join studentsclasses sc
on s.id = sc.studentid
group by s.name
order by count(sc.id)
limit 1
) v
on s.name = v.name
Answers for this question.
How can I modify my query to return only those 7 students with 0 classes.
SELECT
s.name, count(sc.id) AS classes
FROM
students s
LEFT JOIN studentsclasses sc ON s.id = sc.studentid
where (SELECT count(sc.id) FROM
students s
LEFT JOIN studentsclasses sc ON s.id = sc.studentid)=0
GROUP BY s.name
ORDER BY count(sc.id);
I have a database with the tables:
Student(SID,Name,Surname,Age)
Registration(StudentID,CourseID)
Course(CID,Name,Cost)
I would like to extract only the name of the courses with students younger than 20. Will the query below do just that?
SELECT C.NAME
FROM Course C
INNER JOIN Registration
INNER JOIN Student S
WHERE CID = CourseID
AND SID = StudentID
AND Age < 20
GROUP BY C.NAME
I would also like to extract the number of students in each course having students younger than 20. Is it correct to do it as below?
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Course C
INNER JOIN Registration
WHERE Age < 20
AND CID = CourseID
AND SID = StudentID
GROUP BY C.NAME
You are missing the ON part for the join otherwise it would just be a CROSS JOIN.
Your first query should look like this if you want just a distinct list of student names:
SELECT DISTINCT C.NAME
FROM Course C
INNER JOIN Registration R ON C.CID = R.CourseID
INNER JOIN Student S ON R.StudentID = S.SID
WHERE Age < 20
Your second query shouldn't really have the C.Name in the select if you want to get just a count unless you want a count of how many students have that name.
SELECT count(*)
FROM Student S
INNER JOIN Registration R ON s.SID = R.StudentID
INNER JOIN Course C ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
First join these tables, then group by Course's PK(CID), Add the HAVING condition to filter the course which has students younger than 20.
Then use Course table to join the result to get the course name and count of students in the course.
SELECT
T1.Name,
T2.StudentCount
FROM
Course T1
INNER JOIN (
SELECT
c.CID,
COUNT(s.SID) AS StudentCount
FROM
Course c
LEFT JOIN Registration r ON c.CID = r.CourseID
LEFT JOIN Student s ON s.SID = r.StudentID
GROUP BY c.CID
HAVING COUNT(IF(s.Age < 20, 1, NULL)) > 0
) T2 ON T1.CID = T2.CID
More correctly, you should move the conditions of the join, to the join statements themselves by including them in the on clause instead of the where. While the results may not change in this instance, if you were to start including outer joins you would encounter difficulties.
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
There's a fiddle here showing it in action: http://sqlfiddle.com/#!9/c3b8f/1
Your first query will also produce the results you want, but again, you should move the join predicates to the join itself. Also, you don't need to perform the grouping just to get distinct values, mysql has an expression for that called distinct. So rewritten, the first query would look like:
SELECT DISTINCT C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20.
Again, the results are the same as what you have already but it is easier to 'read' and will put you in good stead when you move on to other queries. As it stands you have mixed implicit and explicit join syntax.
This fiddle demonstrates both queries: http://sqlfiddle.com/#!9/c3b8f/4
edit
I may have misinterpreted your original question - if you want the total number of students enrolled in a course with at least one student under 19, you can use a query like this:
select name, count(*)
from course c
inner join registration r
on c.cid = r.courseid
where exists (
select 1
from course cc
inner join registration r
on cc.cid = r.courseid
inner join student s
on s.sid = r.studentid
where cc.cid = c.cid
group by cc.cid
having min(s.age) < 20
)
group by name;
Again with the updated fiddle here: http://sqlfiddle.com/#!9/c3b8f/17
There are three tables
Students, Courses and Registration
Students has id, name columns
Courses has also course.id, course.name
and there is third table joining the Students and Courses table
Registration : stu_id, course_id
One Student can take one or many courses.
I would like to find the name of Students registered in only one course.
Try with INNER JOIN
SELECT S.id, S.name
FROM students S
INNER JOIN registration R ON S.id = R.stu_id
GROUP BY S.id, S.name
HAVING COUNT(*) = 1
Like below:
SELECT s.id, s.name
FROM students s
LEFT JOIN registration r ON s.id = r.stu_id
GROUP BY s.id, s.name
HAVING COUNT(r.course_id) = 1
select s.*
from (
select r.stu_id stu_id
from Registration r
group by r.stu_id
having count(*) == 1) ra
join Students s on s.id = ra.stu_id;
This one is more efficient.
It's unlikely that your schema has null fields. Therefore, it doesn't matter which kind of join, inner or left, you use.
I have three tables in Mysql that are link together:
Profile (ID, Name, Stuff..)
Contact(ID, ProfileID,desc,Ord)
Address(ID,ProfileID, desc, Ord)
Now I need to select all profile from the profile table, with the “desc” field from Contact and Address where Ord = 1. (this is for a search function where in a table I’ll display the name, main contact info and main Address of a client.
I can currently do this with three separate SQL request:
SELECT Name, ID FROM Profile WHERE name=”bla”
Then in a foreach loop, I’ll run the other two requests:
SELECT ProfileID, desc FROM Contact WHERE ProfileID=MyProfileID AND Ord=1
SELECT ProfileID, desc FROM Address WHERE ProfileID=MyProfileID AND Ord=1
I know you can do multiple SELECT in one query, is there a way I could group all three SELECT into one query?
You should be able to JOIN the tables on the profile.id and the profileid in the other tables.
If you are sure the profileid exists in all three tables, then you can use an INNER JOIN. The INNER JOIN returns matching rows in all of the tables:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
inner join contact c
on p.id = c.profileid
inner join address a
on p.id = a.profileid
where p.name = 'bla'
and c.ord = 1
and a.ord = 1
If you are not sure that you will have matching rows, then you can use a LEFT JOIN:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
left join contact c
on p.id = c.profileid
and c.ord = 1
left join address a
on p.id = a.profileid
and a.ord = 1
where p.name = 'bla'
If you need help learning JOIN syntax, here is a great visual explanation of joins
This query below only selects column when an ID from Profile table has atleast one match on tables: Contact and Address. If one or both of them are nullable, use LEFT JOIN instead of INNER JOIN because LEFT JOIN displays all records from the Left-hand side table regardless if it has a match on other tables or not.
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID
INNER JOIN Address c
ON a.ID = c.ProfileID
WHERE b.ORD = 1 AND
c.ORD = 1 AND
a.Name = 'nameHERE'
The LEFT JOIN version:
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID AND b.ORD = 1
INNER JOIN Address c
ON a.ID = c.ProfileID AND c.ORD = 1
WHERE a.Name = 'nameHERE'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
i have created working demo as your requirement :
The query bellow will retrieve all matching records from the database.its retrieving profile id,name stufff and description of contact tables
select p.id,p.name,p.stauff,c.descr,a.descr from profile as p
inner join contact as c on c.profileid=p.id
inner join address as a on a.profileid=p.id
where p.name="bla" and c.ord=1 and a.ord=1