多个 TSQL 行中的多个重叠日期需要减少为汇总行

Posted

技术标签:

【中文标题】多个 TSQL 行中的多个重叠日期需要减少为汇总行【英文标题】:Multiple Overlapping dates in multiple TSQL Rows needs to be reduced to a summary row 【发布时间】:2020-05-04 20:46:08 【问题描述】:

我遇到的情况是,我们的系统为系统上的最终用户的登录活动创建了多个重叠行。我不知道它为什么这样做,但确实如此。我将在下面添加几行作为示例:

 RN2                  UserRegistryID LoginTime               LogoutTime              FinalLoginTime FinalLogoutTime
-------------------- -------------- ----------------------- ----------------------- -------------- ---------------
1                    x89889         2018-05-15 12:56:30.000 2018-05-15 13:08:24.873                
2                    x89889         2018-06-26 09:08:59.000 2018-06-26 09:22:24.003                
3                    x89889         2018-06-26 09:22:58.000 2018-06-26 09:51:02.057                
4                    x89889         2018-11-09 12:50:58.000 2018-11-09 13:33:56.250                
5                    x89889         2019-02-12 13:16:17.000 2019-02-12 13:18:39.293                
6                    x89889         2019-02-12 13:19:38.000 2019-02-12 13:38:02.627                
7                    x89889         2019-02-19 13:52:00.000 2019-02-19 14:22:18.000                
8                    x89889         2019-02-19 14:23:34.000 2019-02-19 15:24:02.000                
9                    x89889         2019-03-03 13:20:52.000 2019-03-03 13:29:50.000                
10                   x89889         2019-03-03 13:30:25.000 2019-03-03 15:55:02.247                
11                   x89889         2019-06-21 12:19:35.000 2019-06-21 12:34:01.103                
12                   x89889         2019-09-17 07:55:06.000 2019-09-17 09:08:26.007                
13                   x89889         2019-09-19 20:22:40.000 2019-09-19 20:23:01.723                
14                   x89889         2019-09-21 23:21:43.000 2019-09-22 00:50:10.867                
15                   x89889         2019-09-23 00:16:50.000 2019-09-23 00:55:35.183                
16                   x89889         2019-10-13 22:35:43.000 2019-10-13 23:21:34.000                
17                   x89889         2019-10-13 23:16:29.000 2019-10-14 00:18:55.000                
18                   x89889         2019-10-14 00:16:09.000 2019-10-14 00:47:25.003                
19                   x89889         2019-10-14 12:24:24.000 2019-10-14 12:45:19.000                
20                   x89889         2020-01-07 15:07:42.000 2020-01-07 15:28:49.093                
21                   x89889         2020-01-29 14:29:41.000 2020-01-29 15:05:08.223                
22                   x89889         2020-02-10 12:31:04.000 2020-02-10 12:37:36.343                
23                   x89889         2020-03-17 19:10:31.000 2020-03-17 19:52:37.003                
24                   x89889         2020-03-24 15:23:47.000 2020-03-24 15:54:15.000                
25                   x89889         2020-03-24 16:31:42.000 2020-03-24 16:46:56.000                
26                   x89889         2020-03-25 21:04:43.000 2020-03-25 21:27:11.000                
27                   x89889         2020-03-25 21:45:56.000 2020-03-25 22:50:19.003                
28                   x89889         2020-03-26 01:39:16.000 2020-03-27 09:30:09.003                
29                   x89889         2020-03-26 18:15:36.000 2020-03-26 18:35:50.000                
30                   x89889         2020-04-09 18:47:32.000 2020-04-09 19:06:02.000                
31                   x89889         2020-04-16 19:13:57.000 2020-04-16 20:02:04.000                
32                   x89889         2020-04-24 09:13:07.000 2020-04-24 09:33:16.000     

因此,RN2 列按照这些事件发生的顺序对这些事件进行排序,并且该序列对每个用户进行分区和递增 - 由 UserRegistryID 定义。如您所见,第二行的登录时间在第一行的注销时间之前。第三行也是如此。所以通过查看这个,你可以推断这应该被识别为一个“会话”,从第一行的 LoginTime 和最后一行的 LogoutTime 开始。我一直在试图弄清楚如何解决这个问题,并尝试了多种方法,但都没有成功。有谁知道我如何实现这一目标?

非常感谢您提前提供的任何帮助。

【问题讨论】:

这似乎是空白和孤岛问题。你试过什么?为什么它不起作用?向我们展示您的实际预期结果,并向我们提供我们可以使用的示例数据(不是图片)也将有助于我们为您提供帮助。 @Larnu 这有帮助吗? 【参考方案1】:

这是一个孤岛问题。这是一种使用lag() 和累积sum() 定义连续重叠行组的方法,然后您可以聚合:

select
    userRegistryID,
    min(rn2) min_rn2,
    max(rn2) max_rn2,
    min(loginTime) minLoginTime,
    max(logoutTime) maxLogoutTime,
    count(*) no_records
from (
    select
        t.*,
        sum(case when loginTime <= lagLogoutTime then 0 else 1 end)
            over(partition by userRegistryID order by rn2) grp
    from (
        select 
            t.*,
            lag(logoutTime) over(partition by userRegistryID order by rn2) lagLogoutTime
        from mytable t
    ) t
) t
group by userRegistryID, grp
order by userRegistryID, minLoginTime

或者,如果您不想聚合行,而是将每个会话的开始和结束日期添加到每一行,您可以这样做:

select
    rn2,
    userRegistryID,
    loginTime,
    logoutTime,
    min(loginTime) over(partition by userRegistryID, grp) finalLoginTime,
    max(logoutTime) over(partition by userRegistryID, grp) finalLogoutTime
from (
    select
        t.*,
        sum(case when loginTime <= lagLogoutTime then 0 else 1 end)
            over(partition by userRegistryID order by rn2) grp
    from (
        select 
            t.*,
            lag(logoutTime) over(partition by userRegistryID order by rn2) lagLogoutTime
        from mytable t
    ) t
) t
order by userRegistryID, rn2

【讨论】:

嗨@GMB 谢谢你。与此有关的一个问题,也是我没有澄清的错是同一用户的其他行将是不同的会话。我将在附加评论中添加所有数据。为了回答您的问题,我想保留这些行,但只在最后两列中添加最终会话登录和注销时间。 @Larnu - 我希望这会有所帮助,我已将原始问题更新为包含文本而不是图像。我最初尝试了查看上一行和下一行并标记它们的 fw 组合,但那是在我意识到你可以有很多行之前,这是真的。我认为答案可能在于嵌套的while循环,但是1,我没时间了,2,我没那么聪明!

以上是关于多个 TSQL 行中的多个重叠日期需要减少为汇总行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 或 MariaDB 将单行中的日期范围分散到多个行中

如何为行中的多个集合计算存储过程中两个日期之间的差异

TSQL PIVOT/UNPIVOT 多个汇总列

需要一种更好的方法来将一个列值与同一表行中的多个列值进行比较

如何在linux命令行中替换多个文件中的字符串

计算多个日期范围内有多少个重叠日期