Reputation: 1951
Need some help with MySQL.
I'm building web shop and I'm having problems with filtering search results with multiple WHERE IN clauses on same column.
I have tables shopitem, filter, filter_option and shopitem_option.
shopitem (Items with name, description, price etc.)
id
title
price
filter (Main filter categories like color, brand, gender, size etc.)
id
name
filter_option (filter options like sizes (S, M, L), colors (black, white) etc.)
id
name
filter_id (filter.id)
shopitem_option (connection between items and options)
id
shopitem_id (shopitem.id)
filter_id (filter.id)
filter_option_id (filter_option.id)
I have items like various Nike Air shoes with different size, color, gender etc...
So in shopitem_option table I have following:
id | shopitem_id | filter_id | filter_option_id
-----------------------------------------------------
1 | Nike Air | Color | black
2 | Nike Air | Color | white
3 | Nike Air | Size | 40
4 | Nike Air | Size | 41
5 | Nike Air | Size | 42
6 | Nike Air | Gender | man
When I'm creating MySQL query it need to be something like this (in pure SQL query instead of 'black', 'men' etc. there are IDs of filter_option.id field)
SELECT shopitem.*
FROM shopitem
LEFT JOIN shopitem_option.shopitem_id = shopitem.id
WHERE
shopitem_option.filter_option_id IN (black) AND
shopitem_option.filter_option_id IN (41,42) AND
shopitem_option.filter_option_id IN (man)
But this does not work. If I search only for size 40, or only for color black, it will return all shoes sizes 40 or all shoes with black color. But if I combine filter to search items with color black and size 40 it returns empty query results.
So, basically user can search for shoes WHERE colors (black OR white) AND size (41 OR 42) AND gender (male). How can i accomplish that ?
Upvotes: 2
Views: 2269
Reputation: 2153
Use it like this
SELECT si.*, GROUP_CONCAT(so.filter_option_id) AS filter_options
FROM shopitem si
LEFT JOIN shopitem_option so ON(so.shopitem_id = si.id)
HAVING
FIND_IN_SET('black', filter_options)
AND FIND_IN_SET('41', filter_options)
AND FIND_IN_SET('man', filter_options)
GROUP BY si.id
For counting the number of si.id from the result you can use like this with subquery
SELECT COUNT(res.id) FROM
(SELECT si.*, GROUP_CONCAT(so.filter_option_id) AS filter_options
FROM shopitem si
LEFT JOIN shopitem_option so ON(so.shopitem_id = si.id)
HAVING
FIND_IN_SET('black', filter_options)
AND FIND_IN_SET('41', filter_options)
AND FIND_IN_SET('man', filter_options)
GROUP BY si.id)
AS res
Upvotes: 1
Reputation: 1090
IN ... AND IN ...
can't work here, because you tell database to select shopitem_option where filter_option_id should be black
and 41
for one same record. Use EXISTS
like this:
SELECT *
FROM shopitem i
WHERE EXISTS (SELECT 1 FROM shopitem_option o WHERE i.id = o.shopitem_id AND o.filter_option_id IN (black))
AND EXISTS (SELECT 1 FROM shopitem_option o WHERE i.id = o.shopitem_id AND o.filter_option_id IN (41, 42))
AND EXISTS (SELECT 1 FROM shopitem_option o WHERE i.id = o.shopitem_id AND o.filter_option_id IN (man))
Upvotes: 3