具有随机时间差异的非连续行之间的日期差异和 T-SQL 中行之间的组

Date difference between non-consecutive rows with random time differences and group between rows in T-SQL

我已经查看了许多不同的问题,但没有任何内容可以回答这个问题。

基本上我们有一个用户列表,他们属于不同的类别。此类别可以重复,这意味着某人可以在几行中属于 A 类,然后在两行中属于 B 类,然后在一段时间内回到 A 类,并且每个类别中没有设定的行数,或者它们是否会重复。 table 显示了数据库中的前三列,我在最后添加了另外两列,显示了我希望能够计算的内容以及如何计算。

我想做的是根据用户第一次进入该类别的时间和他们第一次移动到新类别的时间来计算用户在该类别中的时间。如果他们从类别 A 跳到 B 然后又回到 A,类别 A 应该被视为一个单独的类别。

一直在尝试不同的选项但无济于事,因此非常感谢您的帮助。

...数据差距和孤岛(SO 中对此有很多答案)

declare @t table(userid int, category char(1), datetimestart datetime);

insert into @t(userid, category, datetimestart)
values
(1, 'A', '20210212 08:10:02.000'),(1, 'A', '20210212 08:11:10.000'),
(1, 'B', '20210212 08:12:20.000'),(1, 'B', '20210212 08:14:30.000'),
(1, 'A', '20210212 08:15:20.000'),(1, 'A', '20210212 08:16:10.000'),(1, 'A', '20210212 08:18:40.000'),
(1, 'C', '20210212 08:19:05.000'),(1, 'C', '20210212 08:25:41.000'),
(2, 'A', '20210212 08:10:20.000'),(2, 'A', '20210212 08:14:10.000'),
(2, 'B', '20210212 08:29:05.000'),(2, 'B', '20210212 08:35:41.000'),
(2, 'A', '20210212 08:40:20.000'),(2, 'A', '20210212 08:44:10.000');

select 
    userid, category,
    min(datetimestart) as startdatetime,
    max(datetimestart) as enddatetime
from
(
    select userid ,category,
    case when lead(category) over(partition by userid order by datetimestart) = category 
        then datetimestart
        else lead(datetimestart, 1, datetimestart) over(partition by userid order by datetimestart) 
    end as datetimestart,
    row_number() over(partition by userid order by datetimestart)
    -
    row_number() over(partition by userid, category order by datetimestart) as groupid
    from @t
) as t
group by userid, category, groupid
order by userid, startdatetime;

如果你想要每个类别一行,你可以使用 lag()lead():

select userid, category, datetimestart,
       lead(datetimestart) over (partition by userid order by datetimestart) as datetimeend
from (select t.*,
             lag(category) over (partition by userid order by datetimestart) as prev_category
      from t
     ) t
where prev_category is null or prev_category <> category;

您可以使用您喜欢的任何方法来获得差异。因为这样避免了聚合,所以这应该是最快的方法了。

并且,如果您想删除 END 行,则将上面的内容用作子查询或 CTE 并在外部查询中进行筛选。