计算按列分组的模式

Posted

技术标签:

【中文标题】计算按列分组的模式【英文标题】:Calculate mode grouped by a column 【发布时间】:2020-10-03 07:11:03 【问题描述】:
+--------+-------+
| client | price |
+--------+-------+
|     54 |    25 |
|    648 |    35 |
|     54 |    10 |
|    648 |     8 |
|     54 |    25 |
|    648 |    35 |
+--------+-------+

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

+--------+-------+
| 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.

【问题讨论】:

欢迎来到 SO。请看Why should I provide an MCRE for what seems to me to be a very simple SQL query 请发布 MySQL 的版本以及您使用的数据库库 ($this->database)。 【参考方案1】:

不幸的是,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
)

【讨论】:

这些答案是完美的。但对于任何有同样性能问题的人来说,为了将来参考,PHP 代码似乎比 MySQL 快 3 倍,因为某种原因。【参考方案2】:

对于 MySql 8.0+,您可以使用 row_number() 窗口函数:

select t.client, t.price
from (
  select client, price,
    row_number() over (partition by client order by count(*) desc) rn
  from tablename
  group by client, price
) t
where t.rn = 1;

对于以前的版本,您可以使用相关子查询:

select distinct t.client, t.price
from tablename t
where (t.client, t.price) = (
  select client, price
  from tablename
  where client = t.client
  group by client, price
  order by count(*) desc
  limit 1
);

请参阅demo。

【讨论】:

以上是关于计算按列分组的模式的主要内容,如果未能解决你的问题,请参考以下文章

按列分组,然后自动计算以相同字母开头的多列

MySQL:计算按列分组的值的中位数

按列分组的每行的Python平均值[重复]

按列值分组的列值更新mysql排名

如何按列值的计数进行分组并对其进行排序?

Power Query M - 使用自定义聚合(百分位)按列值分组