【问题标题】:How do I select rows from a MySQL table grouped by one column with required values in another如何从 MySQL 表中选择行,该表按一列分组,另一列具有所需值
【发布时间】:2009-04-01 19:28:56
【问题描述】:

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

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

id product_id 属性值 --------------------------------- 1 1 红色 2 1 小号 3 2色红色 4 2 大号

如何获得 value 为“red”和“small”的所有 product_id?

之前有一个类似的问题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

这可行,但我担心性能,似乎会有更好的方法。

最终这将需要与 products 表连接,或至少用于过滤 products 表:

身份证名称 ------------- 1 产品 1 2 产品 2

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

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

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

【问题讨论】:

  • 在您的示例中,当 group_count 大于 2 时会发生什么?他们将被排除在外。我认为您应该将其设置为 HAVING group_count > 0

标签: sql mysql database


【解决方案1】:

不确定这是否更快,但从您的过滤条件生成的子查询的连接会起作用:

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

【讨论】:

  • 谢谢,这确实有效。我会比较性能。为了让事情变得更复杂,我有另一个属性类型的表以相同的方式加入和过滤,但使用这种方法应该很容易涉及另一个表。
【解决方案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 次,它将如何执行。
  • 它将与任何其他解决方案一样执行,尤其是子查询方法。将表连接到自身并不是性能杀手。
  • SELECT DISTINCT p1.product_id, pn.product FROM properties p1, properties p2, products pn WHERE p1.product_id = p2.product_id AND p1.property = 'size' and p1.value = 'small' AND p2.property = 'color' and p2.value = 'red' AND pn.id = p1.product_id 我测试了这个查询。它会足够快。
【解决方案3】:

您可以将表连接到自身:

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'

【讨论】:

    【解决方案4】:

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

    假设您想要“颜色”与“红色”匹配且“尺寸”与“小”匹配的产品(您在问题中并没有说属性实际上很重要,只是价值),很大一部分问题是,您如何表示所需匹配的列表?它们会作为分隔字符串传递、存储在临时表中、动态构建的 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)
    

    【讨论】:

    • 您说得对,属性名称无关紧要,只是值。在实际表中,名称和值都是外键。我将动态构建 SQL,所需的值来自数组。我最终需要在同一查询中过滤另一个属性类型表。
    • 所以,顾名思义,你是说如果他们的“大小”为“小”或“分布范围”(只是弥补)“小”,则搜索“小”应该对他们一视同仁吗?这不是我编码的目的。当我使用真正的键盘时,我会清理它。
    猜你喜欢
    • 2011-03-30
    • 2020-11-14
    • 2020-05-09
    • 2019-02-18
    • 1970-01-01
    • 2013-06-28
    • 2016-11-27
    • 1970-01-01
    相关资源
    最近更新 更多