Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL join on one-to-many relation where none of the many match a given value

Say I have two tables

User
-----
id
first_name
last_name

User_Prefs
-----
user_id
pref

Sample data in User_Prefs might be

user_id | pref
  2     |  SMS_NOTIFICATION
  2     |  EMAIL_OPT_OUT
  2     |  PINK_BACKGROUND_ON_FRIDAYS

And some users might have no corresponding rows in User_Prefs.

I need to query for the first name and last name of any user who does NOT have EMAIL_OPT_OUT as one of their (possibly many, possibly none) User_Pref rows.

SELECT DISTINCT u.* from User u
LEFT JOIN User_Prefs up ON (u.id=up.user_id)
WHERE up.pref<>'EMAIL_OPT_OUT'

gets me everyone who has at least one row that isn't "EMAIL_OPT_OUT", which of course is not what I want. I want everyone with no rows that match "EMAIL_OPT_OUT".

Is there a way to have the join type and the join conditions filter out the rows I want to leave out here? Or do I need a sub-query?

like image 681
Jacob Mattison Avatar asked Jul 20 '10 20:07

Jacob Mattison


People also ask

Which join is used when there is no match?

The JOIN or INNER JOIN does not return any non-matching rows at all. It returns only the rows that match in both of the tables you join. If you want to get any unmatched rows, you shouldn't use it. The LEFT JOIN and the RIGHT JOIN get you both matched and unmatched rows.

In what type of join rows are returned even when there are no matches through the join criteria on the second table?

LEFT JOIN is used; this will return ALL rows from Table1 , regardless of whether or not there is a matching row in Table2 .

How would you return data from 2 tables even if there are no matches?

The SQL LEFT JOIN returns all rows from the left table, even if there are no matches in the right table. This means that if the ON clause matches 0 (zero) records in the right table; the join will still return a row in the result, but with NULL in each column from the right table.


1 Answers

I personally think a "where not exists" type of clause might be easier to read, but here's a query with a join that does the same thing.

select distinct u.* from User u
left join User_Prefs up ON u.id = up.user_id and up.pref = 'EMAIL_OPT_OUT'
where up.user_id is null
like image 176
Mayo Avatar answered Oct 10 '22 07:10

Mayo