在每个开启事件之后,返回下一个关闭事件。
我正在查询存储在GridDB的运动传感器数据。每一行代表一个传感器状态的变化。
示例数据:
| 时间戳 | 状态 |
|---|---|
| 2021-06-30 10:00:00 | 开启 |
| 2021-06-30 10:00:13 | 关闭 |
| 2021-06-30 10:04:57 | 开启 |
| 2021-06-30 10:24:47 | 关闭 |
| 2021-06-30 10:31:20 | 开启 |
对于每个开启事件,我希望返回下一个关闭事件的时间戳。
预期输出:
| 开启时间 | 关闭时间 |
|---|---|
| 2021-06-30 10:00:00 | 2021-06-30 10:00:13 |
| 2021-06-30 10:04:57 | 2021-06-30 10:24:47 |
| 2021-06-30 10:31:20 | NULL |
这就是我当前正在使用的查询:```sql SELECT a.dt AS on_time, ( SELECT MIN(dt) FROM sensor_table WHERE dt > a.dt AND message = 'OFF' ) AS off_time FROM sensor_table AS a WHERE a.message = 'ON' ORDER BY a.dt;
在我的示例数据中可以返回预期的结果,但我在怀疑这是否是 GridDB 的正确 SQL 模式。
使用带有 MIN(dt) 的相关子查询来检索下一条匹配的行,是推荐做法吗,还是在 GridDB SQL 中有更地道或更高效的方法?
## 解决方案
我发现解决这类问题有两种不同的方法:一种是你的方法,使用子查询并通过对 off 事件进行累计求和来人为地对 on-off 事件进行分组。
不幸的是 GridDB 的 SQL 功能非常有限,无法创建这样的分组。要么在 From 子句中需要使用子查询[不支持],要么在累计求和之后再进行额外的算术运算[不支持]。这使得在这个数据库实现中第一种方法不可行。
于是只剩下你那种方法——关联子查询。通常来说,我会避免把子查询放在 Select 列表中,因为它们通常在每次检索表的一行时迭代执行,效率可能很慢。一个更标准的解法是把“开启”与“关闭”连接起来,并在 Where 子句中放入相关子查询以约束返回的行数。就你的情况来说
Select a.dt as on_time, b.dt as off_time From sensor_table a Left Outer Join sensor_table b Where a.message='on' and b.message='off' and b.dt=(Select min(x.dt) From sensor_table x Where x.message='off' and x.dt>a.dt) ```
我不是说这种写法一定会更高效,但与你将子查询放在Select子句中的情况相比,采用这种方法更有机会触发Select优化。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。