首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >计算设备每天运行的总时间。

计算设备每天运行的总时间。
EN

Database Administration用户
提问于 2023-01-24 20:46:11
回答 1查看 115关注 0票数 1

目前,我有一个sqlite3数据库,可以跟踪我的智能家居设备的状态。主表的架构的相关部分包括

代码语言:javascript
复制
CREATE TABLE states(
    state_id INTEGER NOT NULL,
    entity_id VARCHAR(255),
    state VARCHAR(255),
    last_updated DATETIME
);

我试图计算每一个实体每天在状态中的“开启”时间。目前,我的想法是使用lead函数创建一个列,并在下一次更新时:

代码语言:javascript
复制
CREATE VIEW states_with_next_update AS
  SELECT *, lead(last_updated,1) over (PARTITION BY entity_id) as next_update
  FROM states;

然后,可以从当前时间减去下一次更新时间,以得到每个实体处于特定状态的总时间。

代码语言:javascript
复制
CREATE VIEW states_with_durations AS
  SELECT *, julianday(next_update) - julianday(last_updated) as state_duration, date(last_updated) as day
  FROM states_with_next_update;

对于每种状态的持续时间,我现在可以使用聚合函数来计算每个状态处于"on“状态的总时间:

代码语言:javascript
复制
SELECT day, entity_id, sum(state_duration)
FROM state_with_durations
WHERE state = "on"
GROUP BY day, entity_id;

此方法的唯一问题是,next_update可能不会在同一天内下降,从而导致包含连续两天(或更多)时间的durations,这会导致在第一天进行过多的计算,而在随后的一天则会少计算。

例如,如果一个实体在2022-11-10 20:00至2022-11-11 02:00处于"on“状态,2022-11-10的总数为6,2020年-11-11的总数为0。

所以问题是,我如何使之在上面的例子中,"on“状态的和为2022-11-10天读到4个小时,2022-11-11天读到2个小时?

EN

回答 1

Database Administration用户

发布于 2023-01-25 14:03:07

您需要在您感兴趣的范围内创建所有日期的列表。您可以使用递归CTE (使用start of day修饰符将时间倒带到00:00小时):

代码语言:javascript
复制
WITH RECURSIVE datelist AS (
   SELECT datetime(min(last_updated),'start of day') AS day FROM states
   UNION ALL
   SELECT datetime(day,'+1 day') FROM datelist 
   WHERE datetime(day,'+1 day') < (SELECT max(last_updated) FROM states)
)

此列表可以与states_with_next_update一起生成事件(全部或部分)覆盖的每一天的行。

代码语言:javascript
复制
...
FROM states_with_next_update JOIN datelist 
WHERE last_updated <= datetime(datelist.day,'+1 day') AND next_update > datelist.day

现在,您可以使用min和max的标量版本(不要与聚合混淆)计算事件在当前一天相交的时间。

代码语言:javascript
复制
min(julianday(next_update),julianday(datelist.day,'+1 day')) - max(julianday(last_updated),julianday(datelist.day)) AS state_duration

现在,让我们将所有这些放在您的states_with_durations视图中:

代码语言:javascript
复制
CREATE VIEW states_with_durations AS
  WITH RECURSIVE datelist AS (
       SELECT datetime(min(last_updated),'start of day') AS day FROM states
       UNION ALL
       SELECT datetime(day,'+1 day') FROM datelist 
       WHERE datetime(day,'+1 day') < (SELECT max(last_updated) FROM states)
  )
  SELECT *, min(julianday(next_update),julianday(datelist.day,'+1 day')) - max(julianday(last_updated),julianday(datelist.day)) AS state_duration, date(datelist.day) as day
  FROM states_with_next_update JOIN datelist 
  WHERE last_updated <= datetime(datelist.day,'+1 day') AND next_update > datelist.day;

现在可以使用聚合查询来获得所需的结果。

票数 0
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/322515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档