mysql - MAX() 和 GROUP BY,需要整个结果的 COUNT(*)

标签 mysql sql mysql-8.0

我有一个正在执行的 SELECT 查询,它有一个 MAX() 列和一个 GROUP BY 子句,除了我需要返回给客户端的这个查询的结果,我还需要返回所有结果的总数。

基本上我的查询是这样的:

SELECT unique_id, col1, col2, MAX(col3) as col3
FROM tbl
GROUP BY col1, col2

它通常也会有一个 WHERE 子句。

unique_id 是表的主键。

将此数据返回给客户端时,我还指定了 LIMITOFFSET 子句以限制一次检索的结果数。我的问题是,如果上面的查询没有 LIMITOFFSET 子句,我还需要显示结果的总数,以便客户端可以稍后/增量检索其余部分。

我知道我可以轻松地使用 WITH 临时表来获得我想要的:

WITH temp AS (
    SELECT unique_id, col1, col2, MAX(col3) as col3
    FROM tbl
    GROUP BY col1, col2
)
SELECT count(*) FROM temp

但我担心这样做的效率。 sans-LIMIT-and-OFFSET 查询可能会返回数万行,所以我认为 WITH 获取总计数不是执行此操作的最佳方法。

有没有我没有想到的更有效的方法?或者 WITH 方法是否合适(例如,MySQL 服务器是否足够“智能”,不会分配查询的整个结果集来获取计数)?


示例数据

假设这是我表中的数据:

unique_id  col1  col2  col3
___________________________
1          5     8     30
2          5     8     33
3          5     9     40
4          6     8     30
5          6     8     31
6          6     8     32
7          6     9     39
8          7     8     33
9          7     8     32
10         8     8     34

所以我的 SELECT 查询会返回这个(假设客户端指定了 LIMIT 4 OFFSET 0):

SELECT unique_id, col1, col2, max(col3) as col3
FROM tbl
GROUP BY col1, col2
LIMIT 4
OFFSET 0;
    unique_id  col1  col2  col3
    ___________________________
    2          5     8     33
    3          5     9     40
    6          6     8     32
    7          6     9     39

然后我将不带 LIMITOFFSET 子句的查询用作子查询和SELECT COUNT(*) ,这将返回 6,我会将 6 和结果返回给客户端。

最佳答案

MySQL 8 引入了对 window functions 的支持,包括窗口聚合函数。窗口聚合函数允许您将聚合结果与非聚合数据一起返回。基本上,您可以通过将 OVER 子句附加到它来将常规聚合函数转换为窗口聚合函数,但通常您可能需要指定其他选项,这在链接中有详细说明手册。

您也可以在 GROUP BY 查询中使用窗口聚合函数。在这些情况下,窗口聚合函数将在分组完成后应用于行集。另请注意,添加 LIMIT 不会影响窗口聚合函数的结果。

考虑到以上所有因素,您可以像这样修改原始查询:

SELECT
  unique_id,
  col1,
  col2,
  MAX(col3) as col3,
  COUNT(*) OVER () AS TotalRows
FROM
  tbl
GROUP BY
  col1,
  col2
LIMIT
  4 OFFSET 0
;

一次性获取原始明细数据和行数。 OVER 子句没有附加子句,这意味着它适用于整个行集。

正如我所说,如果一个窗口聚合函数附加到查询,它将忽略 LIMIT 子句。因此,上面的 TotalRows 列将反射(reflect)行数,就好像没有应用限制一样。

关于mysql - MAX() 和 GROUP BY,需要整个结果的 COUNT(*),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52278339/

相关文章:

php - 删除 MySQL 字段值中字符串值开头或结尾的空格

sql - 在 SQL 中将值列表与表行连接

mysql - MySQL 8.0 上的 phpMyAdmin

php - laravel mysql 8连接超时

python - 如何在 OSX 10.6 中将 MySQLdb 与 Python 和 Django 一起使用?

php - laravel 5.5 eloquent 查询构建器在使用查询字符串存储 url 时构建错误的查询

mysql - 使用子查询的 SQL

mysql - 如何永久修复 : Job for mysql. 服务失败,因为控制进程退出并显示错误代码

php - 为什么这个隐藏字段没有被发送到数据库?? MySQL/PHP

sql - 如果语句包含 UNION、INTERSECT 或 EXCEPT 运算符(变体),则 ORDER BY 项必须出现在选择列表中