2013-06-25 7 views
0

Я создаю страницу поиска, подобную AJAX, которая позволяет клиенту выбирать числовые фильтры, которые сужают поиск. Например, пользователь выбрал «iPhone 5» и имеет дополнительные фильтры для емкости (32 ГБ, 64 ГБ) & цвет (черный, белый ..).Совет по разработке базы данных 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 

Вместо 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') 
) 
+0

Я могу видеть, что команда IN - отличный способ упростить запрос для замены многих условий OR, поскольку я хочу использовать по существу многие условия AND, есть ли аналогичная команда IN для MySQL, которая будет делать AND, а не OR? (надеюсь, что имеет смысл) По сути, если пользователь выбирает «32 ГБ» и «Черный», он будет возвращать iPhone-устройство только в запросе, если он имеет атрибуты BOTH «32 ГБ» и «Черный» (например, не возвращается, если он это iPhone 32GB White) – Zabs

+1

Не совсем так, как вы хотите проверить 2 разных строки с помощью AND. Вам нужно либо присоединяться к атрибутам несколько раз, один раз для каждого обязательного атрибута, либо присоединяться к подзапросам атрибутов, которые имеют требуемые значения атрибута, с подсчетом и проверкой того, что счетчик совпадает с количеством требуемых значений атрибута. – 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)); 

Это то, что вы ищете?

EDIT: извини, не заметил, что вы просите запрос с использованием присоединяется

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

Если я правильно прочитал эти требования, проблема заключается в том, что он проверяет устройства, у которых есть атрибут_option_id 19 ИЛИ 47, а не оба. Один из способов, который может быть решён в последнем примере, - это выбрать значение price_id и количество записей в подзапросе с предложением HAVING, чтобы проверить, что счетчик равен 2 (или хотя бы несколько параметров выбраны), хотя это не получится есть дубликаты записей в таблице price_attributes. – Kickstart

+0

отличные ответы ребята! Я использую Framework CodeIgniter, поэтому попытаюсь использовать систему ActiveRecord для генерации запросов как можно больше, но при необходимости я просто буду использовать пользовательские запросы и соответственно изменить их. Еще раз спасибо. – Zabs

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 

Как положить сериализованные детали в поле, это очень плохая идея, и вернется, чтобы укусить вас в будущем !

+0

спасибо за это - я дам оба метода пойти и посмотреть, что соответствует моим требованиям лучшее - еще раз спасибо за советы ребятам! – Zabs