0

我正在构建一个类似 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';

任何关于数据库设计的建议也将不胜感激

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

4

4 回答 4

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 子句来按价格排序:

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));
于 2013-06-25T09:36:38.940 回答
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

至于将序列化的细节放入字段中,这是一个非常糟糕的主意,将来会回来咬你!

于 2013-06-25T09:41:14.273 回答
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')
)
于 2013-06-25T09:51:13.590 回答
0
SELECT * FROM prices WHERE device_id=2939 AND id IN (SELECT price_id FROM prices_attributes WHERE attribute_option_id IN (19,47));

是你要找的吗?

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

于 2013-06-25T09:33:56.977 回答