oracle如何根据值变化对数据进行分组

oracle How to group data based on value change

我已经为此苦苦挣扎了一段时间。我有以下 table,其中存储了有关人员登录和退出系统的数据:

USERID       STATUSDATETIME         CHANGEDLOGGEDIN      LOGGEDIN      ENDDATETIME            STATEDURATION      SEQNO
johndoe      25-08-19 01:39:32      1                    1             25-08-19 01:39:32      0                  0
johndoe      25-08-19 01:39:32      0                    1             25-08-19 01:40:19      47                 0
johndoe      25-08-19 01:40:19      0                    1             25-08-19 01:40:26      7                  1
johndoe      25-08-19 01:40:26      0                    1             25-08-19 01:40:34      8                  2
johndoe      25-08-19 01:40:34      0                    1             25-08-19 01:40:50      16                 0
johndoe      25-08-19 01:40:50      0                    1             25-08-19 01:43:57      187                0
johndoe      25-08-19 01:43:57      1                    0             25-08-19 01:43:57      0                  1

johndoe      25-08-19 01:48:14      1                    1             25-08-19 01:48:14      0                  0
johndoe      25-08-19 01:48:14      0                    1             25-08-19 01:48:48      34                 0
johndoe      25-08-19 01:48:48      0                    1             25-08-19 01:48:53      5                  1
johndoe      25-08-19 01:48:53      0                    1             25-08-19 01:49:00      7                  2
johndoe      25-08-19 01:49:00      0                    1             25-08-19 01:49:08      8                  3
johndoe      25-08-19 01:49:08      0                    1             25-08-19 01:50:26      78                 0
johndoe      25-08-19 01:50:26      0                    1             25-08-19 01:50:33      7                  0
johndoe      25-08-19 01:50:33      1                    0             25-08-19 01:50:33      0                  1

我想要完成的是,基于按用户 ID、statusdatetime 和 seqno 排序的 select,获取每个 "block" 登录的第一个 statusdatetime、最后一个 enddatetime、sum(stateduration) = 1. 这个例子的最终结果是这样的:

select userid, min(statusdatetime), max(enddatetime), sum(stateduration)
from login_table
group by userid,block_of_loggedin

USERID    min(STATUSDATETIME)   max(ENDDATETIME)    sum(STATEDURATION)
johndoe   25-08-19 01:39:32     25-08-19 01:43:57   265
johndoe   25-08-19 01:48:14     25-08-19 01:50:33   139

SQL 不是我的强项,而且我更习惯于 MSSQL 而不是 Oracle,这让我痛苦了好几天。

我尝试过使用分区依据、汇总、连接依据等等,但我无法完成任何接近我期望的事情。

关于如何实现的任何想法?

谢谢大家!

这是一个典型的空岛问题。您可以考虑以下查询:

select 
    userid,
    min(statusdatetime),
    max(enddatetime),
    sum(stateduration)
from (
    select 
        t.*,
        row_number() over(partition by userid order by statusdatetime, enddatetime) rn1,
        row_number() over(partition by userid, loggedin order by statusdatetime, enddatetime) rn2
    from mytable t
) x
where loggedin = 1
group by 
    userid,
    rn1 - rn2
order by 1, 2

它的工作原理是在整个 table 中按日期对每个用户的记录进行排名,并将其与 loggedin 具有相同值的记录组的排名进行比较。当等级之间的差异发生变化时,则开始一个新的岛(组)。

demo on DB Fiddle 与您的示例数据 returns:

USERID  | MIN(STATUSDATETIME) | MAX(ENDDATETIME)  | SUM(STATEDURATION)
:------ | :------------------ | :---------------- | -----------------:
johndoe | 25-08-19 01:39:32   | 25-08-19 01:43:57 |                265
johndoe | 25-08-19 01:48:14   | 25-08-19 01:50:33 |                139