I have a page which shows all cars from DB. I have two filters , both are multiple select filter. For example
filter 1 – Color
Red , green , blue <– All these are checkbox ,can be selected multiple
filter 2 – brand
BMW, Honda , Hyundai <– All these are checkbox ,can be selected multiple
I have done below query
Select * from cars
JOIN term_car_relationships
ON cars.id = term_cars_relationships.car_id
WHERE term_cars_relationships.term_id in (6,2,3)
GROUP BY cars.id
In above query term_id
6 = blue (Color)
2 = green (Color)
3 = BNW (brand)
But with above query I will get all cars which has blue color or green color or BMW brand But how to change in such a way that I get BMW which is blue or green color.
I have 3 tables which handles these categories.
taxonomy table
taxonomy_id | taxonomy_title
1 | Color
2 | Brand
term_list
term_id | term_name | taxonomy_id
1 | Blue | 1
2 | Red | 1
3 | BMW | 2
4 | Honda | 2
term_cars_relationships Table
term_id | car_id
1 | 1
1 | 2
2 | 3
Advertisement
Answer
You can construct your query with separate joins for each term category, and separate filter conditions for each as well.
SELECT cars.*, colorTerms.*, brandTerms.*
FROM cars
INNER JOIN term_car_relationships AS carColorTerms
ON cars.id = carColorTerms.car_id
INNER JOIN term_list AS colorTerms
ON carColorTerms.term_id = colorTerms.term_id AND colorTerms.taxonomy_id = 1
INNER JOIN term_car_relationships AS carBrandTerms
ON cars.id = carBrandTerms.car_id
INNER JOIN term_list AS brandTerms
ON carBrandTerms.term_id = brandTerms.term_id AND brandTerms.taxonomy_id = 2
WHERE colorTerms.term_id IN (6, 2)
AND brandTerms.term_id IN (3)
Of course, to construct this query, you will need to know the terms’ types before the query.
Also, using GROUP BY cars.id
without aggregation is probably a sign of a problem, or just not the right way to get what you want. If you only want the information from the cars
table, you should just SELECT DISTINCT cars.*
. Using GROUP BY
in this manner will end up with results with the data from just one color-brand match for each car.
With the complexity the edit to the original question added, another possibility presents itself….
SELECT cars.* -- You should really just select the fields you want, and may have to in some configurations (see GROUP BY)
FROM cars AS c
INNER JOIN term_car_relationships AS tcr ON c.car_id = tcr.car_id
INNER JOIN term_list AS tl ON tcr.term_id = tl.term_id
WHERE tcr.term_id IN (6, 2, 3)
GROUP BY cars.car_id -- In some configurations of MySQL, and most other RDBMSes, you must specify every SELECTed non-aggregated field here
HAVING COUNT(DISTINCT tl.taxonomy_id)
= ( SELECT COUNT(DISTINCT taxonomy_id)
FROM term_list
WHERE term_id IN (6, 2, 3)
)
Note: This final solution does not actually require you to know term taxonomies ahead of time anymore, and does not grow as more taxonomies need supported; so while it is a little less obvious with what it is doing, is probably definitely worth considering.