如何从一个列中分组的MySQL表中选择具有所需值的行

时间:2009-04-01 19:28:57

标签: sql mysql database

我需要过滤某些属性存储在连接表中且匹配所有必需属性的产品,即用户需要能够通过添加要求逐步缩小搜索范围。

问题实际上只涉及我认为的属性表,而不是连接,给出以下(简化)产品属性表:

id  product_id  property  value
---------------------------------
1   1           color     red
2   1           size      small
3   2           color     red
4   2           size      large

我如何获得所有product_ids,其中值为'red'和'small'?

之前的类似问题was asked但未得到充分回答。一个解决方案涉及一个COUNT和HAVING来获取每组中有多少行所需行的行,例如

SELECT product_id, count(*) AS group_count FROM properties where
value = 'red' OR value = 'small'
GROUP BY product_id
HAVING group_count = 2

这有效但我关注性能,似乎会有更好的方法。

最终需要加入或至少用于过滤产品表:

id  name     
-------------
1   Product 1
2   Product 2

我忘了提到我有两个属性表连接到我需要过滤的产品,一个具有产品的常规属性,另一个具有可用的可配置选项(有点像变体)。 该方案是允许用户过滤以下产品: “显示性别='男性',品牌='耐克'和尺寸=='小'的产品,其中性别和品牌是'属性',尺寸在选项中(可在添加到购物车时配置)

使用带有计数的组的解决方案仍然可以处理2个已连接的表,但它会变得混乱,所需的组计数是第一个表上所需选项的数量乘以第二个表上的数字。

我可以从属性(和另一个表)中获取id然后只做一个选择id IN(ids),匹配两个属性表的一组id,我不喜欢这样做的想法一个很长的ID列表。

4 个答案:

答案 0 :(得分:2)

不确定这是否更快,但是根据过滤条件生成的子查询的连接可以正常工作:

Select p.name, p.id from product p, 
(select product_id from properties where value='red') colors,
(select product_id from properties where value='small') sizes
where p.id=colors.product_id and p.id=sizes.product_id

答案 1 :(得分:2)

SELECT DISTINCT p1.product_id, pn.name 
FROM properties p1, properties p2,
     productNames pn
WHERE p1.product_id = p2.product_id
AND p1.property = 'size' and value = 'small'
AND p2.property = 'color' and value = 'red'
AND pn.id = p1.product_id

答案 2 :(得分:1)

您可以将表格加入到自身:

SELECT
prop1.product_id
FROM
properties prop1
JOIN properties prop2
    ON prop1.product_id = prop2.product_id
WHERE
prop1.property = 'color' and prop1.value = 'red'
and prop2.property = 'size' and prop2.value = 'small'

答案 3 :(得分:1)

又一次遇到属性 - 价值数据模型的一个陷阱。

假设您想要的产品“颜色”匹配“红色”而“尺寸”匹配“小”(您在问题中没有说该属性真正重要,只是价值),很大一部分问题是,你如何表示所需的匹配列表?它们是作为分隔字符串传递,存储在临时表中,SQL是动态构建的还是其他什么?

如果您可以将它们放入表格(临时或其他),则以下查询应该有效。由于子查询,性能将非常依赖于您正在使用的数据量以及索引的方式。此外,如果您在同一产品的表格中最终得到重复的属性,那么它可能会抛弃,所以您可能需要考虑到这一点。

SELECT
    P.*
FROM
    Products P
WHERE
    NOT EXISTS
    (
        SELECT
            *
        FROM
            Product_Search_Template PST
        LEFT OUTER JOIN Properties P2 ON
            P2.property = PST.property AND
            P2.value = PST.value AND
            P2.product_id = P.product_id
        WHERE
            P2.id IS NULL
    )

SELECT
    P.*
FROM
(
    SELECT
        PROP1.product_id,
        COUNT(*) AS match_count
    FROM
        Properties PROP1
    INNER JOIN Product_Search_Template PST ON
        PST.property = PROP1.property AND
        PST.value = PROP1.value
    GROUP BY
        PROP1.product_id
) SQ
INNER JOIN Products P ON
    P.product_id = SQ.product_id
WHERE
    SQ.match_count = (SELECT COUNT(*) FROM Product_Search_Template)