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支持。