MySQL Query with multiple conditions and multiple tables

Lalu picture Lalu · Aug 22, 2013 · Viewed 9.6k times · Source

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.

Answer

Gordon Linoff picture Gordon Linoff · Aug 22, 2013

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.