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 = ?
Related
I have this query
select courses.id, y.qs_world, courses.name_en as name,
courses.description_en as description,
source_link, courses.slug, fee, duration, courses.university_id, college_id,
study_level_id, application_fee, courses.currency_id
from courses
left join university_ranks as y on courses.university_id = y.university_id
and y.year = '2021'
left join universities on courses.university_id = universities.id
left join countries on countries.id = universities.country_id where courses.status = 1
order by ROW_NUMBER() OVER (PARTITION BY countries.id ORDER BY courses.id)
This query is taking too long to execute, but it is working well if I remove the last row.
I used indexing but nothing different.
The EXPLAIN notes are to Using temporary,Using filesort but I want to improve the query without using temporary or filesort
How can I achieve this?
UPDATE:
I tried this query but same speed
SELECT * FROM (
SELECT
`courses`.`id`,`courses`.`status`, `y`.`qs_world`, `courses`.`name_en` as `name`, `courses`.`description_en` as `description`,
`source_link`, `courses`.`slug`, `fee`, `duration`, `courses`.`university_id`, `college_id`,
`study_level_id`, `application_fee`, `courses`.`currency_id`, `countries`.`id` as country_id
FROM
courses
left join `university_ranks` as `y` on `courses`.`university_id` = `y`.`university_id`
and `y`.`year` = '2021'
left join `universities` on `courses`.`university_id` = `universities`.`id`
left join `countries` on `countries`.`id` = `universities`.`country_id`
) UserCourse where status = 1
order by ROW_NUMBER() OVER (PARTITION BY country_id ORDER BY id)
countries.id as country_id --> universities.country_id
then remove
left join `countries` ON `countries`.`id` = `universities`.`country_id`
Move where status = 1 into the inner query.
It seems like
order by ROW_NUMBER() OVER (PARTITION BY country_id ORDER BY id)
could be replaced by
ORDER BY country_id, id
Get rid of the outer query
Don't say LEFT unless the 'right' table might have a missing row. (It confuses the reader as to your intent.)
comment table and post table both has column named user_id
I cannot specify both table's user_id
for using some if else condition later I need both the user_id as a different name (I'm trying to use AS).
I tried different way but query not working:
$sql="SELECT `post_id`, `comment_id`, `comment`, `user_id`, `username`,
`is_marked` `post`.`user_id` AS `p_uid` FROM `comment` INNER JOIN `user` ON
`comment`.`user_id` = `user`.`id` INNER JOIN `post` ON
`user`.`id`=`post`.`user_id` ORDER BY `comment_id` DESC";
$result = mysqli_query($con, $sql);
if ($result) {
while ($row=mysqli_fetch_assoc($result)) {
$post_user_id = $row['p_uid'];
You could alias table name with other name and get column. View example:
SELECT C.comment_id, U.user_id
FROM comment C INNER JOIN user u ON C.user_id = U.id
I would do:
SELECT c.post_id,
c.comment_id,
c.comment,
c.user_id AS c_uid,
c.username,
c.is_marked,
p.user_id AS p_uid
FROM comment c
INNER JOIN user u ON c.user_id = u.id
INNER JOIN post p ON c.user_id = p.id
ORDER BY c.comment_id DESC
Define aliases for the tables, and the selected fields. It makes it simpler to read than putting the table names all the time.
In your PHP you can then reference $row['c_uid'] or $row['p_uid'].
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)
I'm trying to make a query that returns the following:
All users such that:
-They are not an admin or owner account
-They have the same client_id as the project's client_id
-They are not already in the project_users table with entry project_users.project_id = 9
Here is my MySQL query:
SELECT `users`.`id` as id, `users`.`first_name` as first_name, `users`.`last_name` as last_name, `users`.`username` as username
FROM (`users`)
JOIN `projects` ON `projects`.`client_id` = `users`.`client_id` AND projects.id = 9
LEFT OUTER JOIN `project_users` ON `users`.`id` = `project_users`.`user_id`
WHERE `users`.`user_type` != 'Admin'
AND `users`.`user_type` != 'Owner'
For some reason, this query seems to return all non-super(not owner or admin) users with the same client_id as the project, but does NOT exclude those already in the project_users table (ie. the LEFT OUTER JOIN statement isn't working).
Can anyone tell me what is wrong with the query?
Thanks!
You need to add a filter to find the rows that don't match. Also, your query can be helped by using table aliases:
SELECT u.`id` as id, u.`first_name` as first_name, u.`last_name` as last_name, u.`username` as username
FROM `users` u JOIN
`projects` p
ON p.`client_id` = u.`client_id` AND p.id = 9 LEFT OUTER JOIN
`project_users` pu
ON u.`id` = pu.`user_id`
WHERE u.`user_type` not in ('Admin', 'Owner') and
pu.user_id is NULL;
Let's say I have two tables, users and notes. Let's say the schemas look like this:
users
id, name, field2, field3
notes
id, user_id, subject, heading, body, timestamp
What I want to do is select every user, and the LATEST (just 1) note posted by each user based on the timestamp to show in an overview report.
How would I go about doing this? Please note that the DB is MySQL.
Thanks!
select users.name, notes.subject, notes.heading, notes.body
from users, notes
where users.id = notes.user_id
and notes.timestamp = (select max(timestamp) from notes where user_id = users.id)
select u.id, u.name, n.id as note_id, n.subject, n.heading, n.body, n.timestamp
from users u
left outer join (
select user_id, max(timestamp) as timestamp
from notes
group by user_id
) nm
left outer join notes n on nm.user_id = n.user_id and nm.timestamp = n.timestamp
Note that this could potentially return duplicates if the user has two notes with the exact same timestamp. I have assumed this is not the case.
SELECT *
FROM `users`
LEFT JOIN `notes`
ON `user_id` = `users`.`id`
WHERE `notes`.`timestamp` = (
SELECT MAX(`timestamp`)
FROM `notes` AS `notes_1`
WHERE `notes_1`.`user_id` = `notes`.`user_id`
)