Apache IoTDB 表模型如何按分钟去重后进行条件求和?
可以用 date_bin(1m, time) 按分钟分组,内层查询为每分钟选出一个温度值,外层再按条件求和。题目数据中,三个分钟分别计入 85.0、82.0、88.0,预期总和为 253.0。
示例中同一分钟内的温度都相同,可以用 MAX(temperature) 合并重复上报。如果实际数据中同一分钟的温度可能不同,就要先确定取最大值、最早值还是最新值。
为什么原来的 SQL 报错
表模型的时间分组使用 GROUP BY date_bin(...),不能直接套用树模型的 GROUP BY ([start, end), interval) 写法。时间范围应放在 WHERE 中,GROUP BY 关键字也不应整体加反引号。
在 2.0.6 中,分组时应写完整表达式 GROUP BY date_bin(1m, time),避免引用同层 SELECT 中定义的分钟别名。官方文档说明,从 V2.0.11 起才支持直接使用此类别名分组。IoTDB 表模型 GROUP BY 文档
先查看分钟级结果
在同一分钟内温度相同的前提下,可以先执行:
SELECT
date_bin(1m, time) AS minute_time,
MAX(temperature) AS minute_temperature
FROM test
WHERE device_id = 'sensor_01'
GROUP BY date_bin(1m, time)
ORDER BY minute_time;
根据题目数据,预期得到:
| 分钟 | minute_temperature |
|---|---|
| 2024-11-30 00:00 | 85.0 |
| 2024-11-30 00:01 | 82.0 |
| 2024-11-30 00:02 | 88.0 |
这里的 MAX 为每个分钟组选出一个代表值,不会累加该分钟内的重复记录。
再对分钟级结果进行条件求和
将上面的分组结果作为子查询:
SELECT SUM(IF(minute_temperature > 80, minute_temperature)) AS total_temperature
FROM (
SELECT
date_bin(1m, time) AS minute_time,
MAX(temperature) AS minute_temperature
FROM test
WHERE device_id = 'sensor_01'
GROUP BY date_bin(1m, time)
) AS minute_data;
内层先把六条记录合并为三个分钟值,外层再判断这些值是否大于 80。题目数据的预期计算结果是:
85.0 + 82.0 + 88.0 = 253.0
表模型支持在 FROM 中使用表子查询,可以通过两层查询完成这两次聚合。IoTDB 子查询文档
取值规则与边界条件
如果业务要求每分钟取最新的非空温度,可以将内层的 MAX(temperature) 替换为 LAST(temperature);取最早的非空温度则使用 FIRST(temperature)。这些函数的含义不同,不能因为示例结果相同就任意替换。IoTDB 聚合函数文档
阈值判断应保留在外层。例如,同一分钟先上报 85,后上报 75,若规则是取最新值,该分钟就不应计入。提前在内层筛选 temperature > 80 会留下旧值,改变统计含义。
还需注意:
- 若要保留原尝试中的
(2024-11-30T00:00:00, 2024-11-30T00:02:20]范围,应在内层WHERE中增加time > 2024-11-30T00:00:00 AND time <= 2024-11-30T00:02:20。 - 若扩展到多个设备,内层应按
device_id, date_bin(1m, time)分组,避免把不同设备的同一分钟合并。 - 不要用全局的
SUM(DISTINCT temperature)代替分钟分组,否则不同分钟出现的相同温度也会被合并。 - 没有符合条件的值时,
SUM返回NULL;业务要求返回零时,可以在外层使用COALESCE(SUM(IF(minute_temperature > 80, minute_temperature)), 0)。IoTDB 聚合函数的空值规则
备注:内容仅供参考。
