【问题标题】:Date difference between non-consecutive rows with random time differences and group between rows in T-SQLT-SQL中具有随机时间差异的非连续行之间的日期差异和行之间的分组
【发布时间】:2021-02-12 05:41:23
【问题描述】:

我已经浏览了许多不同的问题,但没有任何东西可以回答这个问题。

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

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

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

【问题讨论】:

    标签: sql sql-server gaps-and-islands


    【解决方案1】:

    如果您希望每个类别有一行,您可以使用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 并在外部查询中进行过滤。

    【讨论】:

    • 我一直在玩领先和滞后,但没想到把它放在子查询中
    • 数据并不完美,因此对于滞后(类别)超过(按日期时间开始的用户ID顺序分区),我有时更新为滞后(类别)超过(按日期时间开始的用户ID顺序分区,类别)具有不同类别的两行将具有相同的时间 - 不应该是这种情况,但不幸的是这些场景会偷偷溜进来
    【解决方案2】:

    ...数据差距和孤岛(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;
    

    【讨论】:

    • 。 .如果您仔细查看所需的结果,您会发现这不会产生与 OP 要求的结果相同的结果。
    猜你喜欢
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 2019-07-19
    相关资源
    最近更新 更多