简体   繁体   中英

How to request lists that contain certain items in MySQL

In the application I am developing, the user has to set parameters to define the end product he will get.

My tables look like this :

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

Now only some combinations of parameters are available to the user. In my example, he could get a red round wooden thingy or a green round wooden thingy but not a blue one because I can't produce it.

Let's say the user selected wood and round parameters. How do I make a request to know that there's only red and green available so I can disable the blue option for him ? Or is there some better way to model my database ?

Try the following

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

Or removing the already selected parameters

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)

Let us assume you provide the selected parameters id in the following format

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

I am also assuming you are using some scripting language to help you with your app. Like ruby or php.

I am also assuming you want to avoid putting as much logic into your stored procedure or MySQL queries as much as possible.

Another assumption is that you are using one of the Rapid Application MVC Frameworks like Rails, Symfony or CakePHP.

Your logic would be:

  1. Find all the combinations that contain ALL the parameters in your parameterList and put these found combinations in a list called relevantCombinations
  2. Find all the parameters_combinations that contain at least 1 of the combinations in the list relevantCombinations . Retrieve only the unique parameter values.

First two steps can be solved using simple Model::find methods and a forloop in the frameworks I described above.

If you are not using frameworks, it is also cool to use the scripting language raw.

If you require them in MySQL queries, here are some possible queries. Be aware that these are not necessary the best queries.

First one is

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.

To confirm, look at http://sqlfiddle.com/#!2/16831/3 .

Note how I purposely have a Combination 3 which only has the Parameter 1 but not 7. Therefore the query did not give you back 3, but only 1 and 2. Feel free to tweak the asterisk * in the first line.

Second one is

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

To confirm, look at http://sqlfiddle.com/#!2/16831/5

I do not recommend being a masochist and attempt to get your answer in a single query.

I also do NOT recommend using the MySQL queries I have supplied. It is less masochistic. But sufficiently masochistic for me NOT to recommend this way.

Since you did not indicate any tag other than mysql, I suspect that you are stronger with mysql. Hence my answer contains mysql.

My strongest suggestion would be my first. Make full use of established frameworks and put your logic in the business logic layer. Not in the data layer. Even if you don't use frameworks and just use raw php and ruby, that is still a better place for you to place your logic in than MySQL.

I saw that T gave an answer in a single MySQL query but I can tell you that (s)he considers only 1 parameter.

See this part:

WHERE ParameterId = 7  -- 7 is the selected parameter

You can adapt his/her answer with some trickery using a forloop and appending OR clauses.

Again, I do NOT recommend that in the big picture of building an app.

I have also tested his/her answer with http://sqlfiddle.com/#!2/2eda4/2 . There may be 1 or 2 small bugs.

In summary, my recommendations in descending order of strength:

  1. Use a framework like Rails or CakePHP and the pseudocode step 1 and 2 and as many find as you need. (STRONGEST)
  2. Use raw scripting language and the pseudocode step 1 and 2 and as many simple queries as you need.
  3. Use the raw MySQL queries I created. (LEAST STRONG)

PS I left out the part in my queries as to how to get the name of the Parameters. But given that you can get the ParameterIDs from my answer, I think that is trivial. I have also left out how you may need to remove the already selected parameters (1, 7). Again, that should be trivial to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM