0

I've the follow SQL schema:

+----------+
| products |
+----------+
| id       |
| name     |
+----------+
    ^ 8
    |
    v 1
+-------------+
|   values    |
+-------------+
| value       |
| product_id  |
| property_id |
+-------------+
    ^ 8
    |
    v 1
+------------+
| properties |
+------------+
| id         |
| name       |
+------------+

One product has many properties and a property belongs to many products. The values table is the join table for the many_to_many association between products and properties. And in this table is saved the value of the property for a product.

Now I'm looking for a query to select all products with property x with value a, and property y with value b ecc. My try is this query but return no records:

SELECT DISTINCT 
    products.* 
FROM 
    products 
INNER JOIN 
    product_values 
    ON product_values.product_id = products.id 
INNER JOIN 
    properties 
    ON properties.id = product_values.property_id 
WHERE 
    (properties.name = 'size' AND product_values.value = 'big') 
    AND (properties.name = 'color' AND product_values.value = 'red')

If possible I need a query with no nested select.

3 Answers 3

4

Since a property can not be color and size at the same time you need to use OR in your where clause. Then group the data and check if both are in the group with having

SELECT products.id, products.name
FROM `products` 
INNER JOIN `product_values` ON `product_values`.`product_id` = `products`.`id` 
INNER JOIN `properties` ON `properties`.`id` = `product_values`.`property_id` 
WHERE (properties.name = 'size' AND product_values.value = 'big') 
   OR (properties.name = 'color' AND product_values.value = 'red')
GROUP BY products.id, products.name
HAVING count(distinct properties.name) = 2
Sign up to request clarification or add additional context in comments.

Comments

3

I would do this using group by and having:

select pv.product_id
from product_values pv join
     properties p
     on pv.property_id = p.id
where (p.name, v.value) in ( ('size', 'big'), ('color', 'red') )
group by pv.product_id
having count(distinct p.name) = 2;

Comments

2

Another approach using sum to filter multiple attributes for an entity

SELECT  
  `p`.* 
FROM
  `products` p
  INNER JOIN `product_values` v
    ON `v`.`product_id` = `p`.`id` 
  INNER JOIN `properties`  pr
    ON `pr`.`id` = `v`.`property_id` 
GROUP BY p.id
HAVING SUM (pr.name = 'size' AND v.value = 'big') 
  AND SUM(pr.name = 'color' AND v.value = 'red')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.