Skip to content
Advertisement

Mysql get where not in with a twist

I want to get the firms that dont have contact method main_phone or phone This is my schema

Firms table
+----+-------+
| id | name  |
+----+-------+
|  1 | Firm1 |
|  2 | Firm2 |
|  3 | Firm3 |
+----+-------+

Contacts
+----+----------+---------+
| id |  label   | firm_id |
+----+----------+---------+
|  1 | Contact1 |       1 |
|  2 | Contact2 |       1 |
|  3 | Contact3 |       2 |
|  4 | Contact4 |       3 |
+----+----------+---------+

contact_methods
+----+-------------+------------+
| id | method_type | contact_id |
+----+-------------+------------+
|  1 | main_phone  |          1 |
|  2 | main_fax    |          1 |
|  3 | email       |          1 |
|  4 | main_fax    |          4 |
|  5 | main_fax    |          3 |
|  6 | phone       |          2 |
|  7 | main_mobile |          1 |
|  8 | url         |          4 |
+----+-------------+------------+

and this is my query

SELECT 
firms.id
FROM firms 
JOIN contacts ON (contactable_id = firms.id)
JOIN contact_methods ON contacts.id = contact_methods.contact_id
WHERE 
firms.active = 1
AND
contact_methods.method_type NOT IN ('mobile','phone','main_mobile','main_phone')

I am getting all firms :s

Advertisement

Answer

Your code checks whether each firm has any contact type that does not belong to the list – while you want to ensure that none of the firm contact does.

One option uses aggregation:

select f.*
from firm f
left join contacts c on c.firm_id = f.id
left join contact_methods cm on cm.contact_id = c.id
group by f.id
having not max(cm.method_type in ('mobile','phone','main_mobile','main_phone')) <=> 1

Alternatively, you can use not exists:

select f.*
from firm f
where not exists (
    select 1
    from contacts c
    inner join contact_methods cm on cm.contact_id = c.id
    where c.firm_id = f.id and cm.method_type in ('mobile','phone','main_mobile','main_phone')
)
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement