Extracting data from multiple tables in mysql - php

My problem is to write a SQL query to return the names of all teachers who have taught a course where at least 2 students received a B- or better in the course.
My tables are:
Courses(id, name, teacher_id)
Grades(student_id, course_id, grade)
Students(id, name, email, password)
Teachers(id, name)
I used the following query:
SELECT * FROM grades JOIN teachers WHERE grades.grade = 'B-'
But shows all teacher like

You can use exists() for that to check if for each teacher exists a course that had more then 2 'b-' or better
So your query should be:
SELECT * FROM Teachers t
WHERE EXISTS(SELECT c.teacher_id from Courses c
inner join grades g ON c.id= g.course_id
where t.id = c.teacher_id and g.grade in('B-','B','A-','A','A+')
group by c.teacher_id having count(*) > 1)

This should work:
Select distinct Teachers.name from Courses join Teachers on Courses.teacher_id = Teachers.id where Courses.id in (Select course_id from (Select course_id, count(student_id) as 'total' from Grades where grade = 'B-' or grade = 'B' or grade = 'B+' or grade = 'A-' or grade = 'A' group by course_id) a where a.total > 1)

Related

Properly using Not In clause

Here, the scenario is:
I have 4 tables
Course
Student
Department
EnrollCourse
While a student going to enroll a course a list of courses should be in dropdown from courses table. But course_id which are already in enroll_courses table shouldn't load in that courses dropdown. Because a student can't register single course 2 times. Here I'm using not in operation which will retrieve list of course_id which are not in enroll_courses table.
But I'm getting following error for the query:
You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near 'enroll_courses.course_id LIMIT 0, 25' at line 6
Here is query:
SELECT students.name, students.email,departments.name as d_name,
courses.name as c_name
FROM students JOIN departments on students.department_id=departments.id
JOIN courses on departments.id = courses.department_id
LEFT JOIN enroll_courses on enroll_courses.course_id=courses.id
WHERE courses.id NOT IN (enroll_courses.course_id) AND students.id=8
Anyone who can help me to find the solution?
Try like this,
SELECT students.name ,
students.email ,
departments.name AS d_name ,
courses.name AS c_name
FROM students
JOIN departments ON students.department_id = departments.id
JOIN courses ON departments.id = courses.department_id
JOIN enroll_courses ON enroll_courses.course_id = courses.id
WHERE students.id = 8
AND courses.id NOT IN ( enroll_courses.course_id );
There are several ways to get the desired result, this is close to your original query:
SELECT students.name ,
students.email ,
departments.name AS d_name ,
courses.name AS c_name
FROM students
JOIN departments
ON students.department_id = departments.id
JOIN courses
ON departments.id = courses.department_id
WHERE students.id = 8
-- up to here it's all possible courses
-- now remove already enrolled courses
AND courses.id NOT IN
(
SELECT course_id
FROM enroll_courses
WHERE student_id = 8
)
Or a Correlated version:
AND courses.id NOT IN
(
SELECT course_id
FROM enroll_courses
WHERE student_id = students.student_id
)
Or NOT EXISTS:
AND NOT EXISTS
(
SELECT *
FROM enroll_courses
WHERE student_id = students.student_id
AND course_id = courses.course_id
)

Multiple select queries with multiple where statements

I currently have this query:
SELECT s.firstName, s.lastName, sum(correct) AS score
FROM student s
JOIN test t ON s.id = t.studentid
WHERE t.testType = 1 GROUP BY lastName, firstName
But I also want it to show
WHERE t.testType = 2
and testType 3 and 4 also.
I want to have it all in the same row. Is this possible?
You could use the in style to select from a multiple of different values
SELECT s.firstName, s.lastName, sum(correct) AS score
FROM student s
JOIN test t ON s.id = t.studentid
WHERE t.testType in ( 1,2,3,4 )
GROUP BY lastName, firstName
I think between clause can answer your question - http://www.tutorialspoint.com/mysql/mysql-between-clause.htm
where t.testType between 1 and 4
SELECT s.firstName, s.lastName, b.score, c.score2
FROM student s
JOIN (
SELECT s.id,s.firstName, s.lastName, sum(correct) AS score FROM student s JOIN test t ON s.id = t.studentid WHERE t.testType = 1 GROUP BY lastName, firstName
) b ON (s.id = b.id)
JOIN (
SELECT s.id,s.firstName, s.lastName, sum(correct) AS score2 FROM student s JOIN test t ON s.id = t.studentid WHERE t.testType = 2 GROUP BY lastName, firstName
) c ON (s.id = c.id)
GROUP BY lastName, firstName
I just used a bunch of JOIN statements. It works. Just doesn't show anything if either value is 0.

Join on specific key not working

I have four tables like this:
schoolyear (id)
student (id, schoolyear_id)
test (id)
grade (id, test_id, student_id, score)
A student is associated with a schoolyear (through fk), and a grade is associated with a test and a student through fk's.
I want all students for a particular schoolyear to be returned regardless, and join the test score for the student along with all other fields from the student table if it exists. If not, the score field should be null. Here is what I have:
SELECT *, `student`.`id` as `studentid`
FROM `student`
LEFT JOIN `grade` ON `grade`.`student_id` = `student`.`id`
WHERE `student`.`schoolyear_id` = ?
There's nothing in my current statement telling it a particular test yet, but that's what I want.
SELECT *, `student`.`id` as `studentid`, t.*
FROM `student`
LEFT JOIN `grade` ON `grade`.`student_id` = `student`.`id`
LEFT JOIN `test` t ON `t`.`id` = `grade`.`test_id`
WHERE `student`.`schoolyear_id` = ?
and test_id = ?
Just add the conditional to the ON clause. This will ensure that students stay included, even if there's no grade for that test.
SELECT g.*, s.id
FROM Student s
LEFT JOIN Grade g
ON g.student_id = s.id
AND g.id = ?
WHERE s.schoolyear_id = ?

query with if and count

trying to add if condition to do the following
1- selecting data depending on if that data selected before by the user
2- selecting data depending on how many time that data was selected by all users
3- setting maximum number of how many times the data could be selected by all user
here is my current code as you can see all that i made the first condition and it work fine
$sql=mysql_query(
"SELECT courseid,coursename
FROM newcourses
where (courseid not in (select courseid from applicants)
)"
);
for example :
if i have table newcourses that have these rows
courseid coursename max applicant
1 English standard 3
2 English advance 2
3 Spanish 4
and table applicants have these rows
id name courseid
1 me 1
2 jon 1
3 jake 2
4 sara 2
5 joe 3
so how to do so
Try something like this:
SELECT n.courseid, n.coursename
FROM newcourses n
LEFT JOIN applicants a ON n.courseid = a.courseid
GROUP BY n.courseid, n.coursename
HAVING count(a.id) <=1;
This will get all the courses that don't have any applicants and the ones that have one applicant.
And it doesn't use a subquery that has to run once for every record selected, so you gain on performance also.
This uses a LEFT JOIN between newcourses and applicants tables. This shows any element of newcourses that have records in applicants table but shows also the ones that aren't in the applicants table (that's the reason to use LEFT JOIN).
sqlfiddle demo
If you want to check them separately you can do:
To get the courses with no applicants:
SELECT n.courseid, n.coursename
FROM newcourses n
LEFT JOIN applicants a ON n.courseid = a.courseid
GROUP BY n.courseid, n.coursename
HAVING count(a.id) = 0;
To exclude courses with two applicants:
SELECT n.courseid, n.coursename
FROM newcourses n
LEFT JOIN applicants a ON n.courseid = a.courseid
GROUP BY n.courseid, n.coursename
HAVING count(a.id) != 2;
If you can't have more than two, you can change the != to <
If you end up adding a new column to newcourses with the max number of applicants, you can't put that in an external HAVING COUNT, so you would have to do a subquery:
SELECT n.courseid, n.coursename
FROM newcourses n
LEFT JOIN applicants a ON n.courseid = a.courseid
WHERE n.maxApplicants >= (SELECT count(*)
FROM applicants ap WHERE ap.courseid = n.courseid)
GROUP BY n.courseid, n.coursename
Is this what you want to do ?
$sql = mysql_query(
"SELECT courseid,coursename
FROM newcourses
WHERE (courseid NOT IN (SELECT courseid FROM applicants GROUP BY courseid HAVING( COUNT( courseid ) > 1)))
"
);
"HAVING (COUNT (courseid) > 1))" will return multiples ocurences values of the table "applicants".
You must include all negative rows on subquery by using filter like GROUP BY - HAVING.
SELECT courseid, coursename
FROM newcourses
WHERE courseid NOT IN (SELECT courseid FROM applicants GROUP BY courseid HAVING COUNT(courseid) > 1)
Easier to read:
SELECT courseid, coursename
FROM newcourses
WHERE courseid IN (SELECT courseid FROM applicants GROUP BY courseid HAVING COUNT(courseid) = 1)
SELECT courseid,coursename
FROM newcourses
where courseid not in (select courseid from applicants GROUP BY courseid HAVING COUNT(courseid)=2)
If you want to ignore courseids which are triplets or more use HAVING COUNT(courseid)>1

Select From Inner join - PHP/MYSQL

I am struggling with a MYSQL query - I have 2 tables :
Table 1 (info) containing UID, first_name, last_name.
Table 2 (card) containing UID, pic .
What I am trying to do is get all results into an array:
WHERE UID IN '$ids' AND LEFT(last_name,1) = '$letter' ORDER BY last_name, first_name ASC
I figured an INNER JOIN so my current code is:
("SELECT UID, first_name, last_name, pic FROM
(SELECT info.first_name,info.last_name,card.pic FROM info
INNER JOIN card ON info.UID=card.UID)
WHERE LEFT(last_name,1) = '$letter' ORDER BY last_name, first_name ASC")
This is producing the following error though:
'Every derived table must have it's own alias'.
Am I going about this the right way with inner join, and how do I give the derived table an alias? Thanks in advance!
select b.UID, g.first_name, g.last_name, b.pic
from user_data.general_info g
inner join user_data.Bcards b on g.UID = b.UID
where LEFT(g.last_name, 1) = '$letter'
order by g.last_name, g.first_name asc
The inner query should be named.
SELECT users.UID, users.first_name, users.last_name, users.pic FROM
(SELECT info.first_name,info.last_name,card.pic FROM user_data.general_info
INNER JOIN user_data.Bcards ON general_info.UID=Bcards.UID) users
WHERE LEFT(users.last_name,1) = '$letter' ORDER BY users.last_name, users.first_name ASC

Categories