MySQL - 通过一组数字的所有组合查找逗号分隔值的字段

时间:2012-12-14 11:41:11

标签: php mysql combinations subset powerset

我们在MySQL中有一个产品表,其中每一行都有一个字段,其中包含以逗号分隔的选项值组合成为该产品。在下面的方案中,您可以看到两个表。逗号分隔值的字段是option_ids,例如,它可以看起来像2,5,6,23或4,2,76。这些数字是选项表中存在的选项。

产品:
|product_id|name|description|option_ids|price|

选项:
|option_id|type_id|label|group|pos|count|price|

我们得到的输入是一系列独特的选项。我们希望在option_ids中找到具有这组选项或其子集的每个产品。

我们现在这样做的方法是生成选项数组的powerset,以便我们拥有选项数组的所有可能组合。然后我们生成一个mysql查询,在“OR WHERE”语句中查询所有这些组合。

这里的问题是powerset呈指数级增长,所以当我们有16个唯一选项的数组时,powerset给出了65536种可能性的数组。为了正常工作,我们不得不增加php的内存使用量,但现在我们遇到了MySQL问题,因为查询变得非常庞大。

有没有其他方法可以解决这个问题?

我希望我已经提供了足够的信息,如果没有,请先询问!

编辑: 第三个表格会给我们带来同样的问题,因为我们需要找到子集...它不是说一个选项是一个产品,它可以是一个产品,但它也可以是2或3个产品。例如:选项1,2制作产品A,选项2,3制作产品B,选项4,5,6制作产品C.如果我们有选项数组[1,2,4,5,6]我们希望找到产品A和C.

3 个答案:

答案 0 :(得分:4)

使用第三张表:

  

Product_Option_Assoc(product_id,option_id)

对于产品应具有的每个选项,请在该表中插入一行。这为您提供了产品和选项之间真正的One-to-many关系。选项的数量可以很容易地变化,并且很容易查询提取数据和更新(不需要逗号解析)。

示例查询:获取已提供相关选项的产品:

$options = array(1, 55, 23); // hard coded but could come from a form (remember to validate/cast as ints)
$optionCommaList = implode(',', $options);

SELECT
    p.name
FROM
    Product_Option_Assoc a
LEFT JOIN
    Products p ON p.product_id = a.product_id
WHERE
    a.option_id IN ($optionCommaList);

答案 1 :(得分:0)

使用FIND_IN_SET(str,strlist)会不会这样做?

我不确定它的效率,但会让您轻松搜索具有特定选项的产品。

答案 2 :(得分:0)

通过将选项列表转换为单个字符串,您将失去数据库的所有功能,并迫使您自己使用字符串匹配和其他kludges。使用链接表。这是正确的方式。然后弄清楚如何为它编写查询。

Product_option ( product_id, option_id )

这就是你想要的:

  

示例:选项1,2制作产品A,选项2,3制作产品B,选项4,5,6制作产品C.如果我们有选项数组[1,2,4,5,6]我们会想找到产品A和C.

要改写,您要检索 not 的所有产品都有一个不在查询数组中的选项。这是如何做到的:

SELECT * from Product WHERE NOT EXISTS (
    SELECT product_id id, option_id opt from Product_option 
        WHERE id = Product.product_id AND opt NOT IN (1, 2, 4, 5, 6)
    )

您可以使用加入明确地执行此操作,但在我看来,EXISTS查询更清楚地了解了这个想法。