2013-06-25 78 views
0

我正在構建一個AJAX搜索頁面,它允許客戶選擇一個數字過濾器來縮小搜索範圍。例如,用戶選擇了「iPhone 5」,並且具有額外的容量(32GB,64GB)色彩(黑色,白色..)。MySQL數據庫設計建議 - 使用連接

用戶只能選擇每個類別單選框(這樣他們就可以選擇32GB &黑色)..但他們無法選擇(32GB 64GB & &黑色作爲其中兩個屬於「能力」類)。

我已經在這裏添加了架構上sqlfiddle(請忽略了一個事實我已經刪除它們,他們剛剛與其他一些領域一起去除適當的應用程序存在的主鍵/數據,以儘量減少sqlfiddle)

http://sqlfiddle.com/#!2/964425

任何人都可以提出創建查詢做以下的最佳方式:

Get all the prices for device_id '2939' (iPhone 5) which has the 'attributes' of '32GB' AND 'Black' 

我現在有這一點 - 但對於選擇單個屬性時,這僅適用於:

// search for device with '64GB' & 'Black' attributes (this currently doesn't return any rows) 
SELECT `prices`.* 
FROM (`prices`) 
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id` 
WHERE `prices`.`device_id` = '2939' 
AND `attribute_option_id` = '19' 
AND `attribute_option_id` = '47'; 

// search for device with '64GB' attribute only (this currently DOES return a row) 
SELECT `prices`.* 
FROM (`prices`) 
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id` 
WHERE `prices`.`device_id` = '2939' 
AND `attribute_option_id` = '19'; 

在數據庫設計的任何建議,將不勝感激太

注:我想有「價格」表具有匹配attribute_ids連載中的新列 - 這會不會對不好然而優化(例如,它會比目前的方法慢)

回答

1

由於attribute_option_id是原子值,所以對於相同的行,它不能有兩個不同的值。所以,你的WHERE子句不能匹配任何記錄:

SELECT `prices`.* 
FROM (`prices`) 
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id` 
WHERE `prices`.`device_id` = '2939' 
AND `attribute_option_id` = '19' # Here for one row, attribute_option_id is either 19 
AND `attribute_option_id` = '47'; # of '47'. Cannot be the both 

取而代之的加入,你可以嘗試一個子查詢,如果你覺得這是更具可讀性。我認爲MySQL允許的語法:

SELECT `prices`.* 
FROM `prices` 
WHERE `prices`.`device_id` = '2939' 
AND EXISTS (SELECT * 
       FROM prices_attributes 
       WHERE price_id = `prices`.`id` 
       AND attribute_option_id IN ('19', '47')) 

我不知道MySQL將如何優化上述解決方案。替代方案是:

SELECT `prices`.* 
FROM `prices` 
WHERE `prices`.`id` IN (
    SELECT DISTINCT `price_id` 
     FROM prices_attributes 
     WHERE attribute_option_id IN ('19', '47') 
) 
+0

我可以看到,IN命令是簡化查詢以取代許多OR條件的好方法,因爲我想在本質上使用許多AND條件,是否有類似的IN命令用於MySQL,它將執行AND而不是OR? (希望是有道理的) 本質上,如果用戶選擇「32GB」和「黑色」,它只會返回查詢中的iPhone設備,如果它具有「32GB」和「黑色」屬性(例如,如果它不返回是iPhone 32GB白色) – Zabs

+1

不是直接的,因爲你想用AND來檢查2個不同的行。您需要多次加入屬性,爲每個必需屬性加入一次屬性,或者加入具有require屬性值的屬性的子查詢,並計數並檢查計數是否與所需屬性值的數量相同。 – Kickstart

+0

我明白你的意思了。這可能會變得棘手,因爲屬性的數量會有所不同(例如,某些手機不具備容量並且可能只是有顏色) 我會嘗試多次執行屬性並查看按照您在此評論正上方的評論中提到的方式工作。 – Zabs

0
SELECT * FROM prices WHERE device_id=2939 AND id IN (SELECT price_id FROM prices_attributes WHERE attribute_option_id IN (19,47)); 

這是你在找什麼?

編輯:對不起,沒有注意到你正在使用要求查詢連接

1

我認爲你應該使用IN操作符的attribute_option_id和你動態設置值的查詢;另外,使用group_by你每個價格只有一行,所以實際上你得到所有的價格。除此之外,設計是好的。

在這裏,我已經做出了表率:

SELECT `prices`.* 
FROM (`prices`) 
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id` 
WHERE `prices`.`device_id` = '2939' 
and `attribute_option_id` in ('19','47') 
group by `prices`.`device_id`, `prices`.`price`; 

在這裏,你還可以添加一個訂單條款的價格訂購:

order by `prices`.`price` desc; 

解決這個另一種方法是使用價格不同,如下所示:

select distinct(prices.price) 
from prices 
where prices.device_id = 2939 
and id in (select price_id from prices_attributes where attribute_option_id in (19,47)); 
+0

看起來像一個SWEET解決方案。謝謝!!完全忘記使用IN命令,我會盡快給你一個鏡頭,讓你知道我如何繼續。再次感謝你一定要愛上stackoverflow! – Zabs

+1

如果我正確地閱讀了要求,那麼這裏的問題是它正在檢查具有19或47的attribute_option_id的設備,而不是兩者。最後一個例子中可以解決的一種方法是選擇price_id和子查詢中的記錄數,用HAVING子句檢查計數是2(或者選擇了多個選項),儘管這會失敗price_attributes表中存在重複的記錄。 – Kickstart

+0

一些偉大的迴應傢伙!我使用的是CodeIgniter框架,因此會嘗試儘可能使用ActiveRecord系統來生成查詢 - 但是如果需要的話,我將只使用自定義查詢並進行相應的修改。再次感謝。 – Zabs

1

幾次加入devices_attributes_options表,一旦f或者每個屬性的項目必須

事情是這樣的: -

SELECT * 
FROM devices a 
INNER JOIN prices b ON a.id = b.device_id 
INNER JOIN prices_attributes c ON b.id = c.price_id 
INNER JOIN devices_attributes_options d ON c.attribute_option_id = d.id AND d.attribute_value = '32GB' 
INNER JOIN devices_attributes_options e ON c.attribute_option_id = e.id AND e.attribute_value = 'Black' 
WHERE a.id = 2939 

至於把序列化的詳細信息到現場,這是一個非常糟糕的主意,並會回來咬你的未來!

+0

謝謝你 - 我會給這兩種方法去看看哪些符合我的要求最好 - 再次感謝提示傢伙! – Zabs