【问题标题】:Calculating time with datetime by groups按组使用日期时间计算时间
【发布时间】:2020-07-28 04:25:57
【问题描述】:

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

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 会出现在前一个任务/行中。如果任务经过多个组,它应该计算票在每个组手中的时间。 我知道这很复杂,但也许有人有我可以开始构建的想法。

【问题讨论】:

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


    【解决方案1】:

    这是一个相当复杂的差距和孤岛问题。

    这是一种方法:

    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
    

    在子查询中,我们将行号分配给两个不同分区中的记录(按票证与按票证组),并恢复下一个记录的日期lead()

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

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

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

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

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

    【讨论】:

    • GMB - 这是一个很酷的答案。您可能应该将 UnPause 添加到 where 子句,因为这是暂停所花费的所有时间的来源。
    • @JMabee:实际上暂停时间是在任务类型为 Pause 的记录中出现的(记住我们使用 lead(),而不是 lag())。
    • 如果您查看完整的数据列表,您会看到 group_id 4 在任务暂停之前花费了 20 分钟。其他 2860 分钟是暂停时间。如果您在现有的 WHERE 子句中添加 UnPause 的过滤器,您的查询将完美运行。
    【解决方案2】:

    我实际上认为这很简单。只需使用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 是一个 dbfiddle(感谢 GMB 创建原始 fiddle)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      相关资源
      最近更新 更多