按组计算日期时间的时间

Calculating time with datetime by groups

我有两个 table 票和任务。注册票证后,它会出现在票证 table 中,并且使用票证进行的每个操作都会保存在任务 table 中。工单 table 包括工单创建者、开始和结束日期(如果已关闭)等信息。任务 table 如下所示:

ID  Ticket_ID   Task_type_ID    Task_type   Group_ID    Submit_Date
1   120         1               Opened      3           2016-12-09 11:10:22.000
2   120         2               Assign      4           2016-12-09 12:10:22.000
3   120         3               Paused      4           2016-12-09 12:30:22.000
4   120         4               Unpause     4           2016-12-10 10:30:22.000
5   120         2               Assign      6           2016-12-12 10:30:22.000
6   120         2               Assign      7           2016-12-12 15:30:22.000
7   120         5               Modify      NULL        2016-12-13 15:30:22.000
8   120         6               Closed      NULL        2016-12-13 16:30:22.000

我想计算每组完成任务的时间。开始时间是将工单分配给某个组的时间,结束时间是该组完成任务的时间(如果他们将其分配到其他地方或将其关闭)。但它不应包括暂停时间(task_type_ID 3 到 4)。此外,当工单分配给其他组时,新的组 ID 会出现在之前的 task/row 中。如果任务经过多个组,它应该计算票在每个组手中的时间。 我知道这很复杂,但也许有人有想法可以让我开始构建。

这是一个相当复杂的间隙和孤岛问题。

这是一种方法:

select distinct 
    ticket_id, 
    group_id, 
    sum(sum(datediff(minute, submit_date, lead_submit_date))) 
        over(partition by group_id) elapsed_minutes
from (
    select
        t.*,
        row_number()      over(partition by ticket_id order by submit_date) rn1,
        row_number()      over(partition by ticket_id, group_id order by submit_date) rn2,
        lead(submit_date) over(partition by ticket_id order by submit_date) lead_submit_date
    from mytable t
) t
where task_type <> 'Paused' and group_id is not null
group by ticket_id, group_id, rn1 - rn2

在子查询中,我们将行号分配给两个不同分区内的记录(by tickets vs by ticket and 组),并恢复 的日期接下来记录lead()

然后我们可以使用行号之间的差异来构建 "adjacent" 记录组(工单在同一组中),同时不考虑工单暂停的时间段。聚合在这里发挥作用。

最后一步是计算在每个组中花费的总时间:这处理票证在其生命周期内多次分配给同一组的情况(尽管您的样本数据中没有显示,描述这个问题听起来像是可能会发生)。我们可以用另一层聚合来做到这一点,但我选择了 window 总和和 distinct,这避免了在查询中再添加一层嵌套。

独立执行子查询可能有助于更好地理解逻辑(参见下面的数据库fiddle)。

对于您的示例数据,the query yields:

ticket_id | group_id | minutes_elapsed
--------: | -------: | --------------:
      120 |        3 |              60
      120 |        4 |            2900
      120 |        6 |             300
      120 |        7 |            1440

其实我觉得这很简单。只需使用 lead() 获取下一个提交时间值并按工单和组进行聚合,忽略暂停:

select ticket_id, group_id, sum(dur_sec)
from (select t.*,
             datediff(second, submit_date, lead(submit_date) over (partition by ticket_id order by submit_date)) as dur_sec
      from mytable t
     ) t
where task_type <> 'Paused' and group_id is not null
group by ticket_id, group_id;

Here 是一个 db<>fiddle(感谢 GMB 创建了原始 fiddle)。