GROUP BY子句
使用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时间
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时间和填充间隔
按时间分组时,如果查询的时间范围内有一个窗口不包含数据,则结果将返回一个包含空窗口时间戳的行,并为每个查询字段返回null值。在GROUP BY子句末尾使用fill()函数替换null字段值。如果不包含FILL子句,则默认行为是fill(null)。
fill()提供了以下填充值的操作:
- 数值字面量:用指定的数值字面量替换null值。
- 线性:使用现有值之间的线性插值替换null值。
- 无:删除具有null字段值的行。
- null:保留null值和相关的时间戳。
- 上一个:用最近的非null值替换null值。
有关详细示例,请参阅fill()文档。
GROUP BY time 示例
以下示例使用比特币价格示例数据。
将查询结果按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 |
| … | … |
按标签将查询结果分组并汇总到每周的间隔
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 |
按时间分组,带有偏移
按每小时间隔分组并使用+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 强制第一个时间边界在查询时间范围之外,因此查询对该第一个间隔返回无结果。
按每小时间隔分组并使用-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 集群返回查询结果集中的行数据。如果查询使用了 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 | field |
|---|
| 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 | field |
|---|
| 2022-01-01T00:00:00Z | 4 |
| 2022-01-01T01:00:00Z | 5.25 |
| 2022-01-01T02:00:00Z | 6 |
为什么这些结果包含了查询时间范围之外的时戳?
GROUP BY time()根据指定的间隔创建具有预定义时间边界的窗口。然而,这些边界不是由查询时间范围决定的。但是,查询结果中的聚合值仅使用查询时间范围内的值来计算。
| time | field |
|---|
| 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值。
如果没有两个值进行插值,则使用线性插值填充
fill(linear)如果在查询时间范围内没有在null值之前或之后的值,则不会填充null值。
支持和反馈
感谢您成为我们的社区一员!我们欢迎并鼓励您对InfluxDB和本文档提供反馈和错误报告。要获取支持,请使用以下资源
拥有年度或支持合同的客户可以联系InfluxData支持。