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
我已经为此苦苦挣扎了一段时间。我有以下 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