4

在我的应用程序中,每个产品组都有很多产品,每个产品都有一个制造商。这些关系由 MySQL 存储在product_groups带有id字段的 InnoDB 表中,并products带有id,product_groupmanufacturer字段。

有没有办法找到每个产品组中最常见的制造商,而无需选择子查询?

这就是我目前的做法:

SELECT product_groups.id,
  (
    SELECT manufacturer FROM products
    WHERE product_group = product_groups.id
    GROUP BY manufacturer
    ORDER BY count(*) DESC
    LIMIT 1
  ) manufacturer_mode
FROM product_groups;
4

1 回答 1

5

试试这个解决方案:

SELECT
    a.product_group,
    SUBSTRING_INDEX(GROUP_CONCAT(a.manufacturer ORDER BY a.occurrences DESC SEPARATOR ':::'), ':::', 1) AS manufacturer_mode
FROM
    (
        SELECT
            aa.product_group,
            aa.manufacturer,
            COUNT(*) AS occurrences
        FROM
            products aa
        GROUP BY
            aa.product_group,
            aa.manufacturer
    ) a
GROUP BY
    a.product_group

解释:

这仍然使用子查询的一种形式,但它只执行一次,而不是像在原始示例中那样逐行执行。

它的工作原理是首先选择product_groupid、制造商以及制造商在每个特定组中出现的次数。

子选择在FROM执行后看起来像这样(这里只是弥补数据):

product_group   |   manufacturer   |    occurrences
---------------------------------------------------
1               |   XYZ            |    4
1               |   Test           |    2
1               |   Singleton      |    1
2               |   Eloran         |    2
2               |   XYZ            |    1

现在我们有了子选择结果,我们需要occurences为每个产品组选择字段中具有最大值的行。

在外部查询中,我们再次按字段对子选择进行分组,product_group但这一次,只有product_group字段。现在,当我们在GROUP BY这里进行操作时,我们可以在 MySQL 中使用一个非常引人注目的函数GROUP_CONCAT,我们可以使用它以我们想要的任何顺序将制造商连接在一起。

...GROUP_CONCAT(a.manufacturer ORDER BY a.occurrences DESC SEPARATOR ':::'...

我们在这里所做的是将每个product_groupid 组合在一起的制造商连接在一起,以ORDER BY a.occurrences DESC确保出现最多的制造商出现在连接列表中的第一位。最后,我们将每个制造商与:::. 这个 for 的结果product_group 1将如下所示:

XYZ:::Test:::Singleton

XYZ首先出现,因为它在该occurance字段中具有最高值。我们只想选择XYZ,因此我们将串联包含在 中SUBSTRING_INDEX,这将允许我们仅根据:::分隔符选择列表的第一个元素。

最终结果将是:

product_group    |    manufacturer_mode
---------------------------------------
1                |    XYZ
2                |    Eloran
于 2012-06-27T10:38:18.890 回答