2013-08-21 3 views
0

В приложении, которое я разрабатываю, пользователь должен установить параметры для определения конечного продукта, который он получит.Как запросить списки, содержащие определенные элементы в MySQL

Мои таблицы выглядеть следующим образом:

Categories 
------------- 
Id Name 
1  Material 
2  Color 
3  Shape 


Parameters 
------------- 
Id CategoryId Name 
1  1   Wood 
2  1   Plastic 
3  1   Metal 
4  2   Red 
5  2   Green 
6  2   Blue 
7  3   Round 
8  3   Square 
9  3   Triangle 

Combinations 
------------- 
Id 
1 
2 
... 

ParametersCombinations 
---------------------- 
CombinationId ParameterId 
1    1 
1    4 
1    7 
2    1 
2    5 
2    7 

Теперь только некоторые комбинации параметров доступны пользователю. В моем примере он мог получить красный круглый деревянный предмет или зеленый круглый деревянный предмет, но не синий, потому что я не могу его изготовить.

Предположим, пользователь выбрал дерево и круглые параметры. Как сделать запрос, чтобы узнать, что есть только красный и зеленый, чтобы я мог отключить синий вариант для него? Или есть лучший способ моделирования моей базы данных?

+0

Да, EAV не очень весело! Но у него есть свои возможности. – Strawberry

ответ

0

Допустим, вы обеспечиваете выбранные параметры идентификатор в следующем формате

// I call this a **parameterList** for convenience sake. 
    (1,7) // this is parameter id 1 and id 7. 

Я также если вы используете какой-то язык сценариев, чтобы помочь вам в вашем приложении. Как рубин или php.

Я также предполагаю, что вы хотите избежать как можно большего количества логики в своей хранимой процедуре или MySQL-запросах.

Другое предположение заключается в том, что вы используете одну из Rapid Application MVC Framework, такую ​​как Rails, Symfony или CakePHP.

Ваша логика будет:

  1. Найти все комбинации, которые содержат все параметры в вашем parameterList и поместить эти найденные комбинации в списке под названием relevantCombinations
  2. Найти все parameters_combinations, которые содержат хотя бы 1 комбинации в списке relevantCombinations. Получите только уникальные значения параметров.

Первые два шага могут быть решены с использованием простых методов Model :: find и forloop в рамках описанных выше структур.

Если вы не используете фреймворки, также полезно использовать язык сценариев raw.

Если вы требуете их в MySQL-запросах, вот несколько возможных запросов. Имейте в виду, что это не обязательно лучшие запросы.

Первый из них является

SELECT * FROM (
    SELECT `PossibleList`.`CombinationId`, COUNT(`PossibleList`.`CombinationId`) as number 
    FROM (
     SELECT `CombinationId` FROM `ParametersCombinations` 
     WHERE `ParameterId` IN (1, 7) 
    ) `PossibleList` GROUP BY `PossibleList`.`CombinationId` 
) `PossibleGroupedList` WHERE `number` = 2; 
-- note that the (1, 7) and the number 2 needs to be supplied by your app. 
-- 2 refers to the number of parameters supplied. 
-- In this case you supplied 1 and 7 therefore 2. 

Чтобы подтвердить, посмотрите на http://sqlfiddle.com/#!2/16831/3.

Обратите внимание, что у меня есть комбинация 3, которая имеет только параметр 1, но не 7. Поэтому запрос не дал вам 3, но только 1 и 2. Не стесняйтесь настраивать звездочку * в первой строке.

Второй один является

SELECT DISTINCT(`ParameterID`) 
FROM `ParametersCombinations` 
WHERE `CombinationId` IN (1, 2); 
-- note that (1, 2) is the result we expect from the first step. 
-- the one we call relevantCombinations 

Чтобы подтвердить, посмотрите на http://sqlfiddle.com/#!2/16831/5

Я не рекомендую мазохистом и попытаться получить ответ на свой вопрос в одном запросе.

Я также НЕ рекомендую использовать запрошенные MySQL запросы. Он менее мазохистский. Но достаточно мазохистски для меня НЕ рекомендовать этот путь.

Поскольку вы не указали ни одного тега, кроме mysql, я подозреваю, что вы сильнее с mysql. Следовательно, мой ответ содержит mysql.

Мое самое сильное предложение было бы моим первым. В полной мере используйте установленные рамки и поместите свою логику в уровень бизнес-логики. Не в слое данных. Даже если вы не используете фреймворки и просто используете raw php и ruby, вам все же лучше разместить логику, чем MySQL.

Я видел, что T дал ответ в одном запросе MySQL, но могу сказать вам, что он считает только 1 параметр.

Смотрите эту часть:

WHERE ParameterId = 7 -- 7 is the selected parameter 

Вы можете адаптировать его/ее ответ с некоторой хитростью, используя forloop и добавляющим или положения.

Опять же, я НЕ рекомендую это в общей картине создания приложения.

Я также проверил его/ее ответ с помощью http://sqlfiddle.com/#!2/2eda4/2. Может быть 1 или 2 небольших ошибки.

В целом, мои рекомендации в порядке убывания силы:

  1. Использование такой структуры, как Rails или CakePHP и шаг псевдокод 1 и 2, а также многие find, как вам нужно. (STRONGEST)
  2. Используйте исходный язык сценариев и шаг псевдокода 1 и 2 и столько простых запросов, сколько вам нужно.
  3. Используйте необработанные MySQL-запросы, которые я создал. (НАИМЕНЕЕ СИЛЬЯ)

P.S. Я оставил часть в моих запросах о том, как получить имя параметра. Но, учитывая, что вы можете получить ParameterIDs из моего ответа, я думаю, что это тривиально. Я также забыл, как вам может понадобиться удалить уже выбранные параметры (1, 7). Опять же, это должно быть тривиально для вас.

+0

Сначала я начинал с процедурного PHP, но мне нужно было что-то более чистое, поэтому я пересмотрел его и подумал, что лучше использовать фреймворк. Теперь я намереваюсь использовать Yii, но это мой первый раз, используя фреймворк, поэтому я не уверен, как он будет обрабатываться. Спасибо за ответ, я более уверен в своих выборах сейчас. – Loonie

+0

Вы также можете использовать Yii. –

0

Попробуйте выполнить следующие действия

SELECT p.*, pc.CombinationId 
FROM Parameters p 
-- get the parameter combinations for all the parameters 
JOIN ParametersCombinations pc 
    ON pc.ParameterId = p.Id 
-- filter the parameter combinations to only combinations that include the selected parameter 
JOIN (
    SELECT CombinationId 
    FROM ParametersCombinations 
    WHERE ParameterId = 7  -- 7 is the selected parameter 
) f ON f.CombinationId = pc.CombinationId 

или удалением уже выбранных параметров

SELECT p.*, pc.CombinationId 
FROM Parameters p 
JOIN ParametersCombinations pc 
    ON pc.ParameterId = p.Id 
JOIN (
    SELECT CombinationId 
    FROM ParametersCombinations 
    WHERE ParameterId IN (7, 1) 
) f ON f.CombinationId = pc.CombinationId 
WHERE ParameterId NOT IN (7, 1) 
Смежные вопросы