当查询有 GROUP BY 时如何获得总数的百分比?

Posted

技术标签:

【中文标题】当查询有 GROUP BY 时如何获得总数的百分比?【英文标题】:How to get a percentage of total when the query has a GROUP BY? 【发布时间】:2013-01-25 05:40:41 【问题描述】:

假设我有一个包含电影演员姓名和他们看过的电影的非标准化表格。例如。

CREATE TABLE movies_actors (
  movies_actors_id INT,
  movie VARCHAR(255),
  actor VARCHAR(255),
  PRIMARY KEY (movies_actors_id)
);

我发送SELECT actor, COUNT(1) FROM movies_actors GROUP BY actor 以了解该演员参演了多少部电影。但我也想了解该演员参演电影的百分比。

我想我可以这样做:

SELECT
  actor,
  COUNT(1) AS total,
  COUNT(1) / (SELECT COUNT(1) FROM movies_actors) * 100 AS avg
FROM movies_actors
GROUP BY actor;

但这似乎... idk... 恶心。

有什么想法吗?

【问题讨论】:

请注意,由于 mysql 引擎的工作方式,count(*) 将具有与 count(1) 完全相同的性能,并且我认为在语义上更正确 【参考方案1】:

对于大型集合,JOIN 可能比子查询执行得更好。

SELECT ma.actor
     , COUNT(1) AS total
     , COUNT(1) / t.cnt * 100 AS `percentage`
  FROM movies_actors ma
 CROSS
  JOIN (SELECT COUNT(1) AS cnt FROM movies_actors) t
 GROUP
    BY ma.actor
     , t.cnt  

对于大型集合,并且当返回很大比例的行时,JOIN 操作通常可以胜过子查询。在你的情况下,它不是一个相关的子查询,所以 MySQL 不应该多次执行,所以它可能没有任何区别。

注意COUNT(1) 的非粉丝...我们可以用COUNT(*)IFNULL(SUM(1),0) 替换任何和所有出现的COUNT(1) 以获得相同的结果。

【讨论】:

SELECT 列表的表达式#3 不在 GROUP BY 子句中,并且包含在功能上不依赖于 GROUP BY 子句中的列的非聚合列“t.cnt”;这与 sql_mode=only_full_group_by 不兼容 @brahimm:要使语句兼容,只需将 t.cnt 添加到 GROUP BY 子句中。即GROUP BY ma.actor, t.cnt。内联视图(派生表)t 保证只返回一行(如果运行成功,否则抛出错误)。【参考方案2】:

当您想从同一个表中获取操作数据时,请执行自交叉连接。

SELECT
m.actor,
COUNT(m.actor) AS total,
(COUNT(m.actor) / t.total_movies) * 100 AS avg
FROM movies_actors m
cross (select count(*) as total_movies from movies_actors) t
GROUP BY m.actor;

【讨论】:

【参考方案3】:

不使用连接和多重查询:-

select actor,counter,  100 * counter / @total as percentage
from(
select actor, 
        case when actor is null
            then @total := count(*)
            else count(*)
        end as counter
    from movies_actors 
    group by actor
    with rollup
) mytable

【讨论】:

【参考方案4】:

我不确定它是否“更好”,但你可以做一个 SUM 并在其他地方做数学:

SELECT actor,
    COUNT(1) AS total,
    SUM(oneMoviePercentPts) AS percentage
FROM movies_actors
CROSS JOIN 
(
    SELECT 100 / CAST(COUNT(1) AS DECIMAL(15,4)) AS oneMoviePercentPts 
    FROM movies_actors
) t
GROUP BY actor

我希望 MySQL 优化器足够聪明,不会多次执行您的子查询,但连接语法明确说明了这一点。

【讨论】:

【参考方案5】:

这对我有用:

SELECT tmpTotal.yearmonth, tmpTotal.rec_count, 
      (tmpTotal.rec_count / @myCumul) * 100 AS myPercentage
FROM
(
  SELECT tmpResult.*, @myCumul := @myCumul + tmpResult.rec_count AS myNewCumul
  FROM
  (
    SELECT date_format(d.created_at, '%Y/%m') as yearmonth, count(*) rec_count
    FROM cf4a_webapp.factTable d 
      join cf4a_webapp.dimTable c on (d.client_id = c.id)
    WHERE c.id = 25 
      AND d.created_at >= '2019-01-01 00:00:01' 
      AND d.created_at < '2020-01-01 00:00:01'
    GROUP BY yearmonth
  ) tmpResult
  JOIN (SELECT @myCumul := 0) tmpCumul
) tmpTotal;

【讨论】:

以上是关于当查询有 GROUP BY 时如何获得总数的百分比?的主要内容,如果未能解决你的问题,请参考以下文章

在 GROUP BY 查询中除以值

如何在休眠中使用group by获取查询结果的总数?

使用 GROUP BY 查询计算百分比

优化 PostgreSql 查询以获取找到的记录总数和基于多个 group by 的分页所需的有限行数

涉及的 SQL 查询问题(我猜是 SUM、Group By、Order by?也许是总数,甚至计数)

SQL GROUP BY子句,使用AVG在DATESPAN计算中获得浮点数2精度