I have three tables products, properties and product_properties. The subset of table structures and values are given below:
products
---------------------------------------------
| id | name | description | price |
---------------------------------------------
| 1 | Camera | Color Camera | 100 |
| 2 | Lens 1 | Camera Lens 1 | 20 |
| 3 | Lens 2 | Camera Lens 2 | 30 |
---------------------------------------------
properties
------------------------------------------
| id | name | display |
------------------------------------------
| 1 | lens_mount | Lens Mount |
| 2 | image_circle | Image Circle |
| 3 | focal_length | Focal Length |
| 4 | lens_family | Lens Family |
------------------------------------------
product_properties
------------------------------------------------
| id | value | product_id | property_id |
------------------------------------------------
| 1 | F-Mount | 2 | 1 |
| 2 | C-Mount | 3 | 1 |
| 3 | 42.01 mm | 2 | 2 |
| 4 | 13.00 mm | 3 | 2 |
| 5 | 10.00 | 2 | 3 |
| 6 | 12.00 | 3 | 3 |
| 7 | Standard | 1 | 4 |
| 8 | Standard | 2 | 4 |
| 9 | Standard | 3 | 4 |
------------------------------------------------
Here is my output condition:
Find all the Lenses for Camera 1 (match camera and lens by lens_family, which is 'Standard' here) which have lens_mount = 'F-Mount' and image_circle >= 40 mm and focal_length > 5
I tried following query for this:
SELECT * FROM products
INNER JOIN product_properties ON products.id = product_properties.product_id
INNER JOIN properties ON properties.id = product_properties.property_id
WHERE (product_properties.value = 'Standard')
AND (properties.name = 'lens_mount' AND product_properties.value = 'F-Mount')
AND (properties.name = 'image_circle' AND product_properties.value >= ABS('40 mm'))
AND (properties.name = 'focal_length' AND product_properties.value >= 5)
However this query only gives correct result if there is only one condition. With all the conditions it doesn't give any value. I tried with OR in place of AND in the where condition but that also didn't help to get the correct output.
Can anyone sortout this please. Thanks in advance.
You want to do the logic in the having
clause rather than in the where
clause:
SELECT products.id
FROM products
INNER JOIN product_properties ON products.id = product_properties.product_id
INNER JOIN properties ON properties.id = product_properties.property_id
group by products.id
having sum(properties.name = 'lens_family' AND product_properties.value = 'Standard') > 0 and
sum(properties.name = 'lens_mount' AND product_properties.value = 'F-Mount') > 0 and
sum(properties.name = 'image_circle' AND product_properties.value >= ABS('40 mm')) > 0 and
sum(properties.name = 'focal_length' AND product_properties.value >= 5) > 0;
You are looking for a set of properties on a single product. No single row can match all the conditions -- they conflict with each other. Instead, use the group by
clause to bring the rows together for a given product. Then count the number of rows that match each condition.
Each clause in the having
corresponds to one of your original clauses in the where
statement, enclosed by sum()
. This counts the number of rows that match. The conditions ensure that there is at least one row for each property.