简体   繁体   中英

Select all from table where another query retuns no results

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:

  • Don't use LIKE to match id values.
  • Don't use SELECT * . Instead, name the columns you want in your result set.
  • The sequence of 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM