tags:

views:

54

answers:

2

I'm trying to create a filter for a list (of apartments), with a many-to-many relationship with apartment features through the apartsments_features table.

I would like to include only apartments that have all of some features (marked 'Yes' on a form) excluding all the ones that have any of another set features (marked 'No'). I realized too late that I couldn't use INTERSECT or MINUS in MySQL.

I have a query that looks something like:

SELECT `apartments`.* FROM `apartments` WHERE `apartments`.`id` IN (
    SELECT `apartments`.`id` FROM `apartments` INTERSECT (
        SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 103 
INTERSECT SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 106
    ) MINUS (
    SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 105 UNION 
    SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 107)
)
ORDER BY `apartments`.`name` ASC

I'm pretty sure there's a way to do this, but at the moment my knowledge is restricted to little more than simple left and right joins.

+1  A: 

You could try something like this:

SELECT apartment_id
FROM
(
    SELECT apartment_id
    FROM apartments_features
    WHERE feature_id IN (103, 106)
    GROUP BY apartment_id
    HAVING COUNT(*) = 2
) T1
LEFT JOIN
(
    SELECT apartment_id
    FROM apartments_features
    WHERE feature_id IN (105, 107)
) T2
ON T1.apartment_id = T2.apartment_id
WHERE T2.apartment_id IS NULL

Join the result of this query to the apartments table to get the name, etc.

Mark Byers
How does this work, if I'm only excluding. Since it's a long list of 'Yes' and 'No', at any one time I could only exclude some results, or include only some e.g. if I have only Yeses or Nos.
Zahymaka
@Zahymaka: If you are only excluding the query can be made a lot simpler.
Mark Byers
Thanks a lot. Bannister's code worked better with what I wanted as I needed to tack on other wheres. I did upvote your answer though. I learnt something for it which should come in handy at some point during this project.
Zahymaka
+1  A: 

A slightly different way of doing it:

select a.*
from apartments a
join apartments_features f1 
on a.apartment_id = f1.apartment_id and f1.feature_id in (103,106) -- applicable features
where not exists
(select null from apartments_features f2
 where a.apartment_id = f2.apartment_id and f2.feature_id in (105,107) ) -- excluded features
group by f1.apartment_id
having count(*) = 2 -- number of applicable features
Mark Bannister
Thanks. I needed to move the WHERE up for your query though, as mysql threw an error if where came after group by. Thank you very much!
Zahymaka
D'oh! I should have spotted that! Query amended accordingly - thanks.
Mark Bannister