MySQL数据库设计建议 - 使用连接

时间:2013-06-25 09:01:54

标签: mysql database database-design schema

我正在构建一个类似于搜索页面的AJAX,它允许客户选择一个数字过滤器来缩小搜索范围。例如,用户选择了“iPhone 5”并具有额外的容量过滤器(32GB,64GB)和颜色(黑色,白色......)。

用户每个类别只能选择一个单独的收音机(因此他们可以选择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';

对数据库设计的任何建议也将受到赞赏

注意:我想在'price'表中有一个新的列,它具有匹配的attribute_ids序列化 - 这对于优化是不利的(例如它会比当前方法慢)

4 个答案:

答案 0 :(得分: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));

答案 1 :(得分:1)

多次加入devices_attributes_options表,每个属性一次必须

这样的事情: -

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

至于将序列化细节放入某个领域,这是一个非常糟糕的主意,将来会再次咬你!

答案 2 :(得分: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

如果您觉得更具可读性,可以尝试子查询,而不是JOIN。我认为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')
)

答案 3 :(得分:0)

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

这是你要找的吗?

编辑:抱歉,没有注意到你要求使用连接查询