PostgreSQL - 聚合日志数据 - 最小/最大时间直到另一个会话

时间:2017-03-04 00:17:43

标签: postgresql

我有一个有效的日志文件表....

id  timestamp    user    job     action
--------------------------------------------
1       7:00    bob     22      did x
2       7:15    bob     22      did q
3       7:30    joe     22      did z
4       8:00    bob     22      did y
5       8:10    bob     56      did x
6       8:11    joe     22      did a
7       8:12    bob     56      did e
8       8:15    joe     45      did u
9       8:24    bob     22      BACK to do w
10      8:32    bob     22      did p
11      8:45    joe     45      did n
12      8:47    joe     56      fixed bobs z

...等......

我正在尝试汇总每个用户花在每个工作上的时间。

作业中的时间从第一个(用户/作业)开始,然后在用户更改作业时停止:

  • Bob在8:10改变了 - 所以他从7点到8点工作了22个
  • 然后从8:10到8:12工作56
  • 然后他从8:24到8:32重新回到了工作22

如何为每位用户提取开始/停止时间? 目的是确定间隔并汇总每个工作花费的总时间 - 能够按用户和工作总和。

我很想知道能够创造这个:

start   stop    job     user
-----------------------------
7:00    8:00    22      bob
7:30    8:11    22      joe
8:10    8:12    56      bob
8:15    8:45    45      joe
8:24    8:32    22      bob

我可以编写一个脚本来完成循环和查询......但这似乎应该是SQL - 它超出了我的微不足道的SQL技能 - 即使谷歌帮助我发现自己很困惑!

提前致谢!

2 个答案:

答案 0 :(得分:2)

您可以使用窗口函数lag()sum()在两个内部查询中指定系列,最后找到这些系列的min()max()

select 
    min(timestamp) as start,
    max(timestamp) as stop,
    job, username
from (  
    select timestamp, username, job, sum(switch) over w as series
    from (
        select 
            timestamp, username, job, 
            (job is distinct from lag(job) over w)::int as switch
        from my_log
        window w as (partition by username order by timestamp)
        ) s
    window w as (order by username, timestamp)
    ) s
group by username, job, series
order by 1;

  start   |   stop   | job | username 
----------+----------+-----+----------
 07:00:00 | 08:00:00 |  22 | bob
 07:30:00 | 08:11:00 |  22 | joe
 08:10:00 | 08:12:00 |  56 | bob
 08:15:00 | 08:45:00 |  45 | joe
 08:24:00 | 08:32:00 |  22 | bob
 08:47:00 | 08:47:00 |  56 | joe
(6 rows)    

Look here to see how it works.

答案 1 :(得分:0)

您可以在插入新行之前创建一个触发器,选择您尝试插入新记录的用户的最后一次(开始),然后减去新时间和时间开始,最后更新该记录放下子结果

declare ini_time time;
declare _id int;
select id,max(timestamp) from logs where user = new.user
  into _id,ini_time;
set ini_time = new.timestamp-ini_time;
update logs set during_time = ini_time where id=_id;

这是触发器指令的想法