📣

TiDB Cloud Serverless 现已更名为
Starter
!此页面由 AI 自动翻译,英文原文请见
此处。

Aggregate (GROUP BY) Functions

本文档描述了 TiDB 支持的聚合函数的详细信息。

支持的聚合函数

本节介绍 TiDB 中支持的 MySQL GROUP BY 聚合函数。

名称描述
COUNT()返回满足条件的行数
COUNT(DISTINCT)返回不同值的个数
SUM()返回总和
AVG()返回参数的平均值
MAX()返回最大值
MIN()返回最小值
GROUP_CONCAT()返回连接后的字符串
VARIANCE(), VAR_POP()返回总体标准差方差
STD(), STDDEV(), STDDEV_POP返回总体标准差
VAR_SAMP()返回样本方差
STDDEV_SAMP()返回样本标准差
JSON_ARRAYAGG()以单个 JSON 数组形式返回结果集
JSON_OBJECTAGG()以包含键值对的单个 JSON 对象形式返回结果集
  • 除非另有说明,否则组函数会忽略 NULL 值。
  • 如果在不包含 GROUP BY 子句的语句中使用组函数,则等同于对所有行进行分组。

此外,TiDB 还提供以下聚合函数:

  • APPROX_PERCENTILE(expr, constant_integer_expr)

    该函数返回 expr 的百分位数。constant_integer_expr 参数表示百分比值,是范围在 [1,100] 的常数整数。百分位 Pkk 代表百分比)表示数据集中至少有 k% 的值小于或等于 Pk

    该函数仅支持 数值类型日期时间类型 作为 expr 的返回类型。对于其他返回类型,APPROX_PERCENTILE 仅返回 NULL

    以下示例演示如何计算 INT 列的第50百分位数:

    DROP TABLE IF EXISTS t; CREATE TABLE t(a INT); INSERT INTO t VALUES(1), (2), (3);
    SELECT APPROX_PERCENTILE(a, 50) FROM t;
    +--------------------------+ | APPROX_PERCENTILE(a, 50) | +--------------------------+ | 2 | +--------------------------+ 1 行结果(0.00 秒)
  • APPROX_COUNT_DISTINCT(expr, [expr...])

    该函数类似于 COUNT(DISTINCT),用于统计不同值的个数,但返回近似结果。它采用 BJKST 算法,在处理具有幂律分布的大型数据集时显著减少内存消耗。此外,对于低基数数据,该函数提供高精度,同时保持高效的 CPU 利用率。

    以下示例演示如何使用该函数:

    DROP TABLE IF EXISTS t; CREATE TABLE t(a INT, b INT, c INT); INSERT INTO t VALUES(1, 1, 1), (2, 1, 1), (2, 2, 1), (3, 1, 1), (5, 1, 2), (5, 1, 2), (6, 1, 2), (7, 1, 2);
    SELECT APPROX_COUNT_DISTINCT(a, b) FROM t GROUP BY c;
    +-----------------------------+ | approx_count_distinct(a, b) | +-----------------------------+ | 3 | | 4 | +-----------------------------+ 2 行结果(0.00 秒)

除了 GROUP_CONCAT()APPROX_PERCENTILE()APPROX_COUNT_DISTINCT 函数外,以上所有函数都可以作为 Window functions 使用。

GROUP BY 修饰符

从 v7.4.0 版本开始,TiDB 的 GROUP BY 子句支持 WITH ROLLUP 修饰符。更多信息请参见 GROUP BY modifiers

SQL 模式支持

TiDB 支持 SQL 模式 ONLY_FULL_GROUP_BY,启用后 TiDB 会拒绝存在歧义的非聚合列的查询。例如,启用 ONLY_FULL_GROUP_BY 后,以下查询是非法的,因为 SELECT 列表中的非聚合列 "b" 没有出现在 GROUP BY 子句中:

DROP TABLE IF EXISTS t; CREATE TABLE t(a BIGINT, b BIGINT, c BIGINT); INSERT INTO t VALUES(1, 2, 3), (2, 2, 3), (3, 2, 3); mysql> SELECT a, b, SUM(c) FROM t GROUP BY a; +------+------+--------+ | a | b | sum(c) | +------+------+--------+ | 1 | 2 | 3 | | 2 | 2 | 3 | | 3 | 2 | 3 | +------+------+--------+ 3 行结果(0.01 秒) mysql> SET sql_mode = 'ONLY_FULL_GROUP_BY'; Query OK, 0 行受影响(0.00 秒) mysql> SELECT a, b, SUM(c) FROM t GROUP BY a; ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'b' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

TiDB 当前默认启用 ONLY_FULL_GROUP_BY 模式。

与 MySQL 的差异

ONLY_FULL_GROUP_BY 的当前实现比 MySQL 5.7 中的要求宽松。例如,假设执行以下查询,期望结果按 "c" 排序:

DROP TABLE IF EXISTS t; CREATE TABLE t(a BIGINT, b BIGINT, c BIGINT); INSERT INTO t VALUES(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); SELECT DISTINCT a, b FROM t ORDER BY c;

为了排序,必须先去重。但去重后,应保留哪一行?这个选择会影响 "c" 的值,从而影响排序,变得任意。

在 MySQL 中,如果 DISTINCTORDER BY 一起使用,只要 ORDER BY 的表达式不满足以下条件之一,查询就会被拒绝:

  • 表达式等于 SELECT 列表中的某一项
  • 表达式引用的所有列都属于查询的 SELECT 列表中的元素

但在 TiDB 中,上述查询是合法的,更多信息请参见 #4254

TiDB 还扩展了标准 SQL,允许在 HAVING 子句中引用 SELECT 列表中的别名表达式。例如,以下查询返回在 orders 表中只出现一次的 "name" 值:

select name, count(name) from orders group by name having count(name) = 1;

TiDB 扩展允许在 HAVING 子句中使用别名来引用聚合列:

select name, count(name) as c from orders group by name having c = 1;

标准 SQL 只允许在 GROUP BY 子句中使用列表达式,因此如下语句是无效的,因为 "FLOOR(value/100)" 是非列表达式:

select id, floor(value/100) from tbl_name group by id, floor(value/100);

TiDB 扩展了标准 SQL,允许在 GROUP BY 子句中使用非列表达式,并认为上述语句是合法的。

标准 SQL 也不允许在 GROUP BY 中使用别名。TiDB 扩展了标准 SQL,允许使用别名,因此另一种写法如下:

select id, floor(value/100) as val from tbl_name group by id, val;

文档内容是否有帮助?