我遇到了从数据库中提取记录的问题。我有产品和产品有属性。有一个数据透视表,用于将product_properties连接到产品。产品可以具有多种属性。
现在我的数据库结构:
产品
| id | title |
-------------------------
| 1 | Mercedes A green |
| 2 | Volvo V40 green |
| 3 | Audi A3 green |
PROPERTY_VALUE
| id | property_id | value |
-------------------------------
| 1 | 1 | Volvo |
| 2 | 1 | Mercedes |
| 3 | 2 | Green |
| 4 | 1 | Audi |
product_property
| product_id | property_id | property_value_id | no column, just info
------------------------------------------------
| 1 | 1 | 2 | Mercedes
| 1 | 2 | 3 | Green
| 2 | 1 | 1 | Volvo
| 2 | 2 | 3 | Green
| 3 | 1 | 4 | Audi
| 3 | 2 | 3 | Green
现在我希望得到所有梅赛德斯或沃尔沃的产品,绿色。我希望product.id 1& 2将被退回。
所以我在考虑这样的事情:
SELECT product.*
FROM product
JOIN product_property ON product.id = product_property.product_id
WHERE
product_property.property_value_id IN (1, 2, 3)
GROUP BY product.id;
但这当然会让我回报所有产品1,2和3。
所以我需要做这样的事情:
SELECT product.*
FROM product
JOIN product_property ON product.id = product_property.product_id
WHERE
(product_property.property_id = 1 AND product_property.property_value_id IN (1, 2))
AND
(product_property.property_id = 2 AND product_property.property_value_id IN (3))
GROUP BY product.id;
但这没有任何回报。
我想我已经接近了,但我无法弄清楚这个查询的最后一步。谁知道......
答案 0 :(得分:1)
您只需添加HAVING
子句:
SELECT product.id, product.title
FROM product
JOIN product_property ON product.id = product_property.product_id
WHERE
product_property.property_value_id IN (1, 2, 3)
GROUP BY product.id, product.title
HAVING COUNT(CASE WHEN property_value_id IN (1,2) THEN 1 END) > 0 AND
COUNT(CASE WHEN property_value_id IN (3) THEN 1 END) > 0
HAVING
子句使用条件聚合来检查与至少一个 property_value_id
1或2 相关的产品和与property_value_id=3
相关。
答案 1 :(得分:0)
你也可以做这样的事情 - 可能比Giorgios的答案慢一点(我怀疑它本身比仅仅运行几个LEFT JOIN慢一点)......
SELECT p.*
FROM product_property x
JOIN property_value y
ON y.property_id = x.property_id
AND x.property_value_id = y.id
JOIN product p
ON p.id = x.product_id
GROUP
BY product_id
HAVING MAX(CASE WHEN x.property_id = 1 THEN y.value END) IN ('Volvo','Mercedes')
AND MAX(CASE WHEN x.property_id = 2 THEN y.value END) IN ('Green');