I'm creating a register web application for someone and I want to make student search to add a student to the activities register slightly more accurate.
At the moment my prepared statement is:
("SELECT * FROM students WHERE first_name LIKE :pattern OR last_name LIKE :pattern OR id LIKE :pattern ORDER BY last_name ASC");
And that works great. I returns a list of all students that match the search query. However after doing that query, for each row that returns I want to check if the students.id and $_GET['activity'] do not appear in the participants table already.
$_GET['activity'] is an ID from activities.id
The final result I want is to display all students that are not already registered on that activity.
Is this possible in one query? As if it is I'd rather do that then have to run a query on each returns result to see whether it should be displayed or not.
I have looked into INNER JOIN as I've used it before, but I don't feel that is what I need. My main issue is how to run that query to check if each result is in the participants table already.
Hopefully that will make sense as I'm finding it hard to work out how to word it in my head.
My table structure:
students - id PRIMARY KEY AI, first_name (varchar255), last_name (varchar255), dob (date)
activities - id PRIMARY KEY AI, title (varchar255), description (varchar255)
participants - id PRIMARY KEY AI, student_id (INT), activity_id (INT)
EDIT Updating this to use the three tables in the question
If you want all students who do NOT have a certain activity, you use a query pattern like this. The LEFT JOIN
retains all the records from the students
table, and places NULL
values in the columns from activities
where the ON
condition fails to match. You then throw in a WHERE
condition to keep only those NULL
values. Like so:
SELECT s.id, s.first_name, s.last_name
FROM students s
LEFT JOIN participants p ON s.id = p.student_id
LEFT JOIN activities a ON p.activity_id = a.activity_id AND a.activity LIKE :act
WHERE a.activity_id IS NULL
AND ( s.first_name LIKE :a OR s.last_name LIKE :b OR etc etc )
If your input is an activity_id
, it's even easier.
SELECT s.id, s.first_name, s.last_name
FROM students s
LEFT JOIN participants p ON s.id = p.student_id AND p.activity_id = :act
WHERE p.activity_id IS NULL
AND ( s.first_name LIKE :a OR s.last_name LIKE :b OR etc etc )
As you've noticed, INNER JOIN
can't do this, because it leaves out the rows from the first table that don't match the ON condition. But those rows are the very ones you want, hence the LEFT JOIN ... WHERE ... IS NULL
.
Beware some things:
id
values.SELECT *
. Instead, name the columns you want in your result set.OR ... LIKE
clauses in your filter for the student table is not going to perform very well.try this query
"SELECT * FROM students WHERE first_name LIKE :pattern OR last_name LIKE :pattern OR id LIKE :pattern AND id NOT IN (select student_id From participants WHERE activity_id = activity)
Here 'activity' is $_GET['activity'] .
You could use a subquery to get the studentid
s that are registered for $_GET['activity']
, and then remove them from the returned rows using NOT IN
in your WHERE
condition.
SELECT * FROM students
WHERE
(first_name LIKE :pattern OR last_name LIKE :pattern OR id LIKE :pattern)
AND
id NOT IN
(SELECT student_id FROM participants WHERE activity_id = :activity)
ORDER BY last_name ASC
where :activity
is the placeholder for $_GET['activity']
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.