PAYATHON 2026

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 聚合函数的空值规则

备注:内容仅供参考。