java - 获取具有多个状态的时间戳之间的平均值

标签 java sql hsqldb usage-statistics

我正在尝试收集有关数据的简单统计信息,例如服务在线时间、服务离线时间、平均值等。我已经找到了一些解决方案,但它们都依赖于某些东西,例如行背靠背 ( ROW_NUMBER -1 ) 或只有两种状态。

我的数据以日志的形式出现,总是在事后(即没有实时数据)。我要弄清楚的最大问题是有两个以上的状态。目前,可能有四种不同的状态(启用、禁用、 Activity 、非 Activity ),我希望能够收集每种状态的数据。

我一次获得一行数据,其中包含服务名称、旧状态、新状态和时间戳。当前数据存储在单个表中。我无法更改数据的提供方式,但我可以更改数据的存储方式,而且我开始认为该表是我的主要缺点。

这里是数据如何最终出现在我的表中的示例:

CREATE TABLE IF NOT EXISTS statusupdates (
  sid int UNIQUE, 
  fullname VARCHAR(64), 
  oldstatus VARCHAR(16), 
  newstatus VARCHAR(16), 
  time TIMESTAMP);

INSERT INTO statusupdates VALUES
(null, 'fictHTTP', 'Off', 'On', '2017-01-01 02:20:00'),
(null, 'faked', 'On', 'Inactive', '2017-01-01 02:25:00'),
(null, 'ipsum', 'Inactive', 'On', '2017-01-01 02:30:00'),
(null, 'resultd', 'On', 'Inactive', '2017-01-01 02:35:00'),
(null, 'ipsum', 'On', 'Active', '2017-01-01 02:40:00'),
(null, 'fictHTTP', 'On', 'Active', '2017-01-01 02:45:00'),
(null, 'faked', 'Inactive', 'Off', '2017-01-01 02:50:00'),
(null, 'ipsum', 'Active', 'Off', '2017-01-01 02:55:00'),
(null, 'resultd', 'Inactive', 'Off', '2017-01-01 03:00:00');

我相信我找到的一种方法是将它缩小到一个项目,例如 resultd .类似于 SELECT fullname, newstatus, time FROM statusupdates WHERE fullname='resultd' ORDER BY time DESC; .然后使用该数据,使用相同的方法进行另一个查询,但向前一步(因为它是降序的)并得到 newstatus从那个记录。当我输入时,它看起来很草率。

或者抓取 oldstatus在第二个查询中,用它来查找 newstatus以下记录。但同样,这可能是草率的。

我知道还有一种方法可以将这两个理论查询结合起来。所以,总而言之,我太过分了,请原谅我!最后,我想查看每种状态的总时间、平均时间等统计数据。我现在最大的障碍是获取查询以提供结果,例如,ipsum 的每个时间戳条目以这样一种方式,我可以从先前的条目中获取持续时间,然后重复此操作,直到它遍历所有记录。

或者,也许,我完全过度思考了这一点,通过将所有数据塞入一个表中而使它变得过于复杂——到目前为止,我已经在这个项目中为不相关的项目做了两次。

附加想法:单个实例,我可以做 SELECT old_status, new_status, time FROM statusupdates WHERE time = '2017-01-01 03:00:00'然后我可以像这样使用 old_status,SELECT old_status, new_status, time FROM statusupdates WHERE time < 'timeStamp' AND new_status = 'oldStatus'然后减去两个时间戳,这将为我提供一个示例的数据。但是,下一步该怎么做,然后下一步,直到它击中所有人。

更新,另一个想法:结合您的一些绝妙建议,向后阅读日志怎么样? 没关系,在这一点上,阅读它们的方向并不重要。 当它遇到状态时,创建一个不完整的记录。它将包含 old_status 和 time_stamp 作为结束时间。然后,当它再次遇到该服务时,它会检查是否 new_status = old_status 并使用 time_stamp 作为 start_time 更新记录。

不过,这似乎会导致大量开销。必须检查每条记录以查看它是否存在,如果不存在则创建一个,如果存在则更新一个。或许这还不算太糟糕?

最佳答案

您可以访问数据库中的窗口函数吗?如果是这样,您可以获得每条记录的下一行的值(按全名分区):

  select  fullname,
          newstatus,
          avg( time_diff ) as avg_time
  from    (
            select  fullname,
                    oldstatus,
                    newstatus,
                    /* get the time value of the next row for this fullname record */
                    lead( time ) over( 
                      partition by fullname 
                      order by time 
                      rows between 1 following and 1 following 
                    ) as next_time,
                    time,
                    next_time - time as time_diff
            from    statusupdates
          ) as a
   group by fullname,
          newstatus

编辑

在没有窗口函数的情况下,您可以通过稍微复杂一点的方式获取next_time:

select a.*,
       b.next_time
from   statusupdates as a
       left join
       (
       select a.fullname,
              a.time,
              min( b.time ) as next_time
       from   statusupdates as a
              left join
              statusupdates as b
              on a.fullname = b.fullname
              and a.time < b.time
       group by a.fullname,
              a.time
       ) as b
       on a.fullname = b.fullname
       and a.time = b.time
;

关于java - 获取具有多个状态的时间戳之间的平均值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41708573/

相关文章:

java - 如何在 Spring Batch 中组合多个监听器(步骤、读取、处理、写入和跳过)

java - 如何从损坏的名称中获取方法参数列表?

SQL 用逗号替换点

mysql - SQL 外连接 2 个表

java - HSQLDB 支持中的文档数据类型

sql - 自动递增 ID 值

java - 无法使用 ColdFusion 10.0 正确初始化 xml 安全库

java - 在 Java 程序中删除一个单词

sql - 如何根据另一列的过滤器更新列?

jdbc - 插入时更新 hsqldb