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

时间:2018-09-11 14:33:17

标签: 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 LIMITOFFSET查询可能返回成千上万的行,因此我认为采用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(*),这将返回{{1 }},然后将6和结果都返回给客户端。

1 个答案:

答案 0 :(得分:3)

MySQL 8引入了对window functions的支持,包括窗口聚合函数。窗口聚合函数允许您返回聚合结果以及非聚合数据。基本上,您可以通过在其上附加OVER子句来将常规聚合函数转换为窗口聚合函数,但是通常可能需要指定其他选项,有关详细信息,请参见链接手册。< / p>

您也可以在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列将反映行数,就好像没有应用限制。