首页 > 解决方案 > 计算按列分组的模式

问题描述

+--------+-------+
| client | price |
+--------+-------+
|     54 |    25 |
|    648 |    35 |
|     54 |    10 |
|    648 |     8 |
|     54 |    25 |
|    648 |    35 |
+--------+-------+

让我们说上面是我的表模式是如何设置的,我想计算price每个client例如最频繁的值。

+--------+-------+
| client | price |
+--------+-------+
|     54 |    25 |
|    648 |    35 |
+--------+-------+

我在 MySQL 中很难做到这一点。我已经在 PHP 中这样做了:

$clientPrices = $this->database->select('design', [
    'clientid',
    'price'
]);

$pricesByClients = [];
foreach ($clientPrices as $value) {
    $pricesByClients[$value['clientid']][] = $value['price'];
}

foreach ($pricesByClients as $key => $value) {
    $priceCount = array_count_values($value);
    $mode = array_search(max($priceCount), $priceCount);
    $pricesByClients[$key] = $mode;
}

return $pricesByClients;

但是,这很慢,我希望我能不能让它变得有点效率,或者用 SQL 来做。

编辑:这是 MySQL 5.* 而不是 8。

标签: phpmysqlgroup-bycountgreatest-n-per-group

解决方案


不幸的是,MySQL 没有内置函数来计算mode().

如果您使用的是 MySQL 8.0,则可以使用窗口函数和聚合:

select client, price
from (
    select client, price, rank() over(partition by client order by count(*) desc) rn
    from mytable
    group by client, price
) t
where rn = 1

在早期版本中,选项是使用having子句和相关子查询进行过滤

select client, price
from mytable t
group by client, price
having count(*) = (
    select count(*)
    from mytable t1
    where t1.client = t.client
    group by t1.price
    order by count(*) desc
    limit 1
)

推荐阅读