2013-08-22 145 views
1

我有三個表產品,屬性和product_properties。表結構和值的子集,給出如下:具有多個條件和多個表的MySQL查詢

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   | 
------------------------------------------------ 

這裏是我的輸出條件:

查找攝像機1(匹配的相機和鏡頭的所有鏡頭由lens_family,這是「標準」在這裏),其具有lens_mount = 'F-摩' 和image_circle> = 40這個毫米和FOCAL_LENGTH> 5

我嘗試以下查詢:

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) 

但是,如果只有一個條件,則此查詢只會給出正確的結果。在所有條件下它都沒有任何價值。我在OR條件下用OR來代替AND,但也沒有幫助獲得正確的輸出。

任何人都可以整理這個請。提前致謝。

回答

2

你想做的邏輯having子句中,而不是where子句中:

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; 

您正在尋找一個單項產品的一組屬性。沒有一行可以匹配所有條件 - 它們相互衝突。相反,使用group by子句將給定產品的行組合在一起。然後計算匹配每個條件的行數。

having中的每個子句對應於where聲明中的一個原始子句,其中包含sum()。這會計算匹配的行數。條件確保每個屬性至少有一行。

+0

我喜歡這個解決方案。如果有不同的屬性可能具有「Standard」作爲值,那麼您應該先爲'HAVING'子句條件('product_properties.value ='Standard'')添加'properties.name ='lens_family'AND'。 – Tom

+0

@Tom。 。 。非常好的一點。我做了修復。 –

+0

謝謝Gordon&Tom,這個解決方案非常完美! – Lalu

0

啊,這個可怕的EVA模式。 第一個認爲你應該做的就是創建一個視圖,按照以下SQL準則數據。

然後,您可以使用該視圖的兩個副本(一個用於相機,一個用於鏡頭)並將它們結合在一起以獲取所需內容。

SELECT p.id 
     ,p.name 
     ,pp1.value as Lens_Mount 
     ,pp2.value as Image_Circle 
     ,pp3.value as Focal_Length 
     ,pp4.value as Lens_Family 
from products p 
left outer join 
     product_properties pp1 
on  pp1.product_id = p.id 
and  pp1.property_id = 1 --lens Mount 
left outer join 
     product_properties pp2 
on  pp2.product_id = p.id 
and  pp2.property_id = 2 --Image Circle 
left outer join 
     product_properties pp3 
on  pp3.product_id = p.id 
and  pp3.property_id = 3 --Focal Length 
left outer join 
     product_properties pp4 
on  pp4.product_id = p.id 
and  pp4.property_id = 3 --Lens Family   
where p.name like 'Lens%' 
0

您應該對每個條件進行OR運算,並計算每個product_id的滿足程度。 所以你GROUP BY product_id和篩選結果使用HAVING子句。

SELECT product_properties.product_id, count(*) as conditions_satisfied 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' 
OR properties.name = 'lens_mount' AND product_properties.value = 'F-Mount' 
OR properties.name = 'image_circle' AND product_properties.value >= ABS('40 mm') 
OR properties.name = 'focal_length' AND product_properties.value >= 5 
GROUP BY product_properties.product_id 
HAVING COUNT(*) = 4 

請注意,如果您確實需要進行數字比較,則可能難以比較字符串屬性值。