使用 GROUP BY 子句,按一个或多个指定的 标签 或指定的时间间隔对数据进行分组。GROUP BY 要求 SELECT 语句中包含 聚合 或 选择器 函数。
语法
SELECT_clause FROM_clause [WHERE_clause] GROUP BY group_expression[, ..., group_expression_n]
- group_expression:用于标识要分组的标签或时间间隔的表达式。可以是 标签键、常量、正则表达式、通配符 (
*) 或 函数表达式。
GROUP BY 子句的行为
GROUP BY tag_key - 按特定标签对数据进行分组GROUP BY tag_key1, tag_key2 - 按多个标签对数据进行分组GROUP BY * - 按所有 标签 对数据进行分组GROUP BY /regex/ - 按匹配正则表达式的标签键对数据进行分组GROUP BY time() - 将数据分组为时间间隔(窗口)
如果查询包含 WHERE 和 GROUP BY,则 GROUP BY 子句必须出现在 WHERE 子句之后。
按一个或多个标签列对数据进行分组。
以下示例使用 比特币价格示例数据。
将数据按单个标签分组
SELECT MEAN(*) FROM bitcoin GROUP BY code
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 27328.848667840004 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 23441.832453919982 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 28054.160950480004 |
将数据按多个标签分组
SELECT MEAN(*) FROM bitcoin GROUP BY code, description
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 27328.848667840004 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 23441.832453919982 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 28054.160950480004 |
按匹配正则表达式的标签键对数据进行分组
SELECT MEAN(*) FROM bitcoin GROUP BY /^[cd]/
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 27328.848667840004 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 23441.832453919982 |
| time | mean_price |
|---|
| 1970-01-01T00:00:00Z | 28054.160950480004 |
按时间分组 (GROUP BY time)
GROUP BY time() 按指定的时间间隔(也称为“窗口”)将数据分组,并对每个时间间隔应用 SELECT 子句中的 聚合 和 选择器 函数。使用 time() 函数 指定要分组的时间间隔。
SELECT_clause FROM_clause WHERE <time_range> GROUP BY time(time_interval[, offset])[, group_expression (...)] [fill(behavior)]
GROUP BY time() 间隔使用预设的整数时间边界,这些边界独立于 WHERE 子句 中的时间条件。输出数据使用窗口开始边界作为聚合时间戳。使用 time() 函数的 offset 参数向前或向后移动时间边界。
按时间分组并填充空缺 (GROUP by time and fill gaps)
按时间分组时,如果查询时间范围内某个窗口不包含数据,结果将返回该空窗口的一行,其中包含空窗口的时间戳以及每个查询字段的 null 值。使用 fill() 函数放在 GROUP BY 子句的末尾 来替换 null 字段值。如果未包含 FILL 子句,则默认行为是 fill(null)。
fill() 为填充值提供以下行为
- numeric literal:用指定数值常量替换 null 值。
- linear:使用现有值之间的线性插值来替换 null 值。
- none:删除带有 null 字段值的行。
- null:保留 null 值和相关时间戳。
- previous:用最近的非 null 值替换 null 值。
有关详细示例,请参阅 fill() 文档。
按时间分组示例
以下示例使用 比特币价格示例数据。
将查询结果分组并聚合到 1 小时窗口中
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-15T00:00:00Z'
GROUP BY time(1h)
| time | mean |
|---|
| 2023-05-01T00:00:00Z | 24494.27265 |
| 2023-05-01T01:00:00Z | 24452.1698 |
| 2023-05-01T02:00:00Z | 23902.666124999996 |
| 2023-05-01T03:00:00Z | 23875.211349999998 |
| 2023-05-01T04:00:00Z | 23855.6441 |
| ... | ... |
按标签将查询结果分组并聚合到 1 周时间间隔中
SELECT
MEAN(price)
FROM bitcoin
WHERE
time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-15T00:00:00Z'
GROUP BY time(1w), code
| time | mean |
|---|
| 2023-04-27T00:00:00Z | 27681.21808576779 |
| 2023-05-04T00:00:00Z | 27829.413580354256 |
| 2023-05-11T00:00:00Z | 26210.24799033149 |
| time | mean |
|---|
| 2023-04-27T00:00:00Z | 23744.083925842704 |
| 2023-05-04T00:00:00Z | 23871.201395652173 |
| 2023-05-11T00:00:00Z | 22482.33174723755 |
| time | mean |
|---|
| 2023-04-27T00:00:00Z | 28415.88231123595 |
| 2023-05-04T00:00:00Z | 28568.010941384844 |
| 2023-05-11T00:00:00Z | 26905.87242099449 |
按时间分组并带偏移量
将查询结果分组并聚合到 1 小时时间间隔中,并将时间边界偏移 +15 分钟
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-02T00:00:00Z'
GROUP BY time(1h, 15m)
| time | mean |
|---|
| 2023-04-30T23:15:00Z | |
| 2023-05-01T00:15:00Z | 29313.6754 |
| 2023-05-01T01:15:00Z | 28932.0882 |
| 2023-05-01T02:15:00Z | 28596.375225000003 |
| 2023-05-01T03:15:00Z | 28578.915075 |
| ... | ... |
请注意,offset 会强制第一个时间边界超出查询时间范围,因此该查询将不返回第一个时间间隔的结果。
将查询结果分组并聚合到 1 小时时间间隔中,并将时间边界偏移 -15 分钟
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-02T00:00:00Z'
GROUP BY time(1h, -15m)
| time | mean |
|---|
| 2023-04-30T23:45:00Z | 29319.9092 |
| 2023-05-01T00:45:00Z | 29285.3651 |
| 2023-05-01T01:45:00Z | 28607.202666666668 |
| 2023-05-01T02:45:00Z | 28576.056175 |
| 2023-05-01T03:45:00Z | 28566.96315 |
| ... | ... |
按时间分组并填充空缺
将查询结果分组并聚合到 30 分钟间隔中,并用 0 填充空缺
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-01T02:00:00Z'
GROUP BY
time(30m)
fill(0)
| time | mean |
|---|
| 2023-05-01T00:00:00Z | 29319.9092 |
| 2023-05-01T00:30:00Z | 29307.4416 |
| 2023-05-01T01:00:00Z | 0 |
| 2023-05-01T01:30:00Z | 29263.2886 |
将查询结果分组并聚合到 30 分钟间隔中,并使用线性插值填充空缺
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-01T02:00:00Z'
GROUP BY
time(30m)
fill(linear)
| time | mean |
|---|
| 2023-05-01T00:00:00Z | 29319.9092 |
| 2023-05-01T00:30:00Z | 29307.4416 |
| 2023-05-01T01:00:00Z | 29285.3651 |
| 2023-05-01T01:30:00Z | 29263.2886 |
将查询结果分组并聚合到 30 分钟间隔中,并用前值填充空缺
SELECT
MEAN(price)
FROM bitcoin
WHERE
code = 'USD'
AND time >= '2023-05-01T00:00:00Z'
AND time < '2023-05-01T02:00:00Z'
GROUP BY
time(30m)
fill(previous)
| time | mean |
|---|
| 2023-05-01T00:00:00Z | 29319.9092 |
| 2023-05-01T00:30:00Z | 29307.4416 |
| 2023-05-01T01:00:00Z | 29307.4416 |
| 2023-05-01T01:30:00Z | 29263.2886 |
结果集
如果查询至少有一行满足条件,InfluxDB 3 Core 将在查询结果集中返回行数据。如果查询使用 GROUP BY 子句,结果集将包含以下内容:
- 查询
SELECT 子句中列出的列 - 一个
time 列,其中包含记录或组的时间戳 - 一个
iox::measurement 列,其中包含记录的测量(表)名称 - 查询
GROUP BY 子句中列出的列;结果集中的每一行都包含用于分组的值
默认时间范围
如果查询未在 WHERE 子句 中指定时间范围,InfluxDB 将使用 默认时间范围 进行过滤和按时间分组。如果查询包含 GROUP BY 子句且未在 WHERE 子句中指定时间范围,则默认时间分组为 默认时间范围,并且结果集中的 time 列将包含该范围的开始时间,例如:
SELECT mean(temp) FROM home GROUP BY room
| time | mean |
|---|
| 1970-01-01T00:00:00Z | 22.623076923076926 |
| time | mean |
|---|
| 1970-01-01T00:00:00Z | 22.16923076923077 |
GROUP BY 子句的注意事项
不能按字段分组
InfluxQL 不支持按**字段**对数据进行分组。
标签顺序无关紧要
在 GROUP BY 子句中列出标签的顺序不会影响数据分组的方式。
按标签分组且无时间范围会返回意外的时间戳
time 列包含 默认时间范围 的开始时间。
按时间分组的数据可能返回意外的时间戳
由于 GROUP BY time() 间隔使用预设的整数时间边界,这些边界与 WHERE 子句 中的时间条件无关,因此结果可能包含超出查询时间范围的时间戳。结果仅表示时间戳在指定时间范围内的对应数据,但输出时间戳由预设时间边界确定。
以下示例按 1 小时间隔对数据进行分组,但 WHERE 子句定义的时间范围仅涵盖一个窗口的一部分
SELECT MEAN(field)
FROM example
WHERE
time >= '2022-01-01T00:30:00Z'
AND time <= '2022-01-01T01:30:00Z'
GROUP BY time(1h)
注意:查询结果数据的第一行中的时间戳出现在查询时间范围的开始时间之前。 原因见此。
示例数据
| time | 字段 |
|---|
| 2022-01-01T00:00:00Z | 8 |
| 2022-01-01T00:15:00Z | 4 |
| 2022-01-01T00:30:00Z | 0 |
| 2022-01-01T00:45:00Z | 8 |
| 2022-01-01T01:00:00Z | 5 |
| 2022-01-01T01:15:00Z | 0 |
| 2022-01-01T01:30:00Z | 8 |
| 2022-01-01T01:45:00Z | 8 |
| 2022-01-01T02:00:00Z | 9 |
| 2022-01-01T02:15:00Z | 6 |
| 2022-01-01T02:30:00Z | 3 |
| 2022-01-01T02:45:00Z | 0 |
查询结果
| time | 字段 |
|---|
| 2022-01-01T00:00:00Z | 4 |
| 2022-01-01T01:00:00Z | 5.25 |
| 2022-01-01T02:00:00Z | 6 |
为什么这些结果包含超出查询时间范围的时间戳?
GROUP BY time() 创建具有预定义时间边界的窗口,这些边界基于指定的时间间隔。然而,这些边界不受查询时间范围的决定,但查询结果中的聚合值仅使用查询时间范围内的值进行计算。
| time | 字段 |
|---|
| 2022-01-01T00:00:00Z | 8 |
| 2022-01-01T00:15:00Z | 4 |
| 2022-01-01T00:30:00Z | 0 |
| 2022-01-01T00:45:00Z | 8 |
| 2022-01-01T01:00:00Z | 5 |
| 2022-01-01T01:15:00Z | 0 |
| 2022-01-01T01:30:00Z | 8 |
| 2022-01-01T01:45:00Z | 8 |
| 2022-01-01T02:00:00Z | 9 |
| 2022-01-01T02:15:00Z | 6 |
| 2022-01-01T02:30:00Z | 3 |
| 2022-01-01T02:45:00Z | 0 |
查询时间范围内无数据时的填充
如果查询时间范围内没有数据,查询将忽略 fill()。这是预期行为。
无前值时的填充
如果查询时间范围内没有前值,fill(previous) 将不会填充 null 值。
插值时不足两个值时的填充
如果查询时间范围内,null 值之前或之后都没有值,fill(linear) 将不会填充 null 值。
支持和反馈
感谢您成为我们社区的一员!我们欢迎并鼓励您对 InfluxDB 3 Core 和本文档提供反馈和错误报告。要获得支持,请使用以下资源
具有年度合同或支持合同的客户可以 联系 InfluxData 支持。