将可变间隔量加在一起

时间:2016-12-16 12:39:56

标签: sql-server

我们刚刚更改了我们的电话系统,现在每个代理都会以15分钟的间隔进行记录,每个事件需要1行

表事件:

empid  | code  |   timestamp  |   duration
5111   |   5   |   09:45:00   |   45
5222   |   2   |   09:58:00   |   120
5111   |   5   |   10:00:00   |   900
5111   |   5   |   10:15:00   |   900
5111   |   5   |   10:15:30   |   30    
5222   |   5   |   11:00:00   |   8   
5222   |   5   |   11:00:05   |   5   

时间戳是在事实之后写的,因此时间戳为9:45:00,持续时间为45,时间为9:44:15,自从时间间隔9:45停止,时间写入,但是我需要9:44:15保存

结果应该给我

empid | code |  timestamp |  duration
5111  |  5   |  09:44:15  |  1875
5222  |  2   |  09:56:00  |  120
5222  |  5   |  10:59:52  |  13

问题是电话被锁定了2小时最大延迟,正如你可以看到我的员工#5222他在两条线上花了13秒......我可以加入同一张桌子10次。 1,以避免存在相同的代码,其中前一行的结束时间=新行的开始时间

这是在MSSQL 2008上

Select e.empid
            ,e.code
            ,convert(time(0),DATEADD(ss,- e.Duration, e.timestamp))
            ,e.duration + isnull(e1.duration,0) + isnull(e2.duration,0)

    from [event] e
left join [event] e0 on 
convert(TIME(0),DATEADD(ss,- e.Duration, e.timestamp)) = e0.timestamp
and 
e.empid = e0.empid
and 
e.code = e0.code

left join [event] e1 on 
convert(TIME(0),DATEADD(ss,- e1.Duration, e1.timestamp)) = e.timestamp
and 
e.empid = e1.empid
and 
e.code = e1.code



left join [event] e2 on 
convert(TIME(0),DATEADD(ss,- e2.Duration, e2.timestamp)) = e1.timestamp  
and 
e2.empid = e1.empid
and 
e2.code = e1.code

--etc......  

where isnull(e0.duration,'-10') = '-10'

这有效但远非最佳......

我宁愿使用聚合函数,但我不知道如何编写它,因为除了上一个时间戳与新表匹配之外没有任何comon键 - 使用此表的持续时间!

重要的是要知道代理5111可以在同一天再次使用代码5,并且我需要2行代替这一行....如果不是,那就太容易了!

提前谢谢你!

1 个答案:

答案 0 :(得分:1)

试试这个。我在代码中评论过,但基本算法

  1. 找到连续的行,即存在匹配一次的行 你减去持续时间
  2. 通过减去延续来找到“原件”,即每次通话的开始
  3. 对于每个原件,找到 next 原件,以便我们可以确定寻找延续件的时间范围
  4. 将所有内容加在一起,并从适用于每个原始
  5. 的延续中添加总持续时间

    希望这会有所帮助,这是一个有趣的挑战!

    declare @data table
    (
        empid int,
        code int,
        [timestamp] time,
        duration int
    );
    
    insert into @data values(5111,5,'09:45',45),
    (5222,2,'09:58',120),
    (5111,5,'10:00',900),
    (5111,5,'10:15',900),
    (5111,5,'10:15:30',30),
    (5222,5,'11:00',8),
    (5222,5,'11:00:05',5),
    -- added these rows to include the situation you describe where 5111 goes again on code 5:
    (5111,5,'13:00',45),
    (5111,5,'13:15',900),
    (5111,5,'13:15:25',25);
    
    -- find where a row is a continuation 
    with continuations as (
        select a.empid, a.code, a.[timestamp] , a.duration
        from @data a 
        inner join @data b on a.empid = b.empid 
            and a.code = b.code
        where dateadd(ss, -a.duration, a.[timestamp]) = b.[timestamp]
    ),
    -- find the "original" rows as the complement of continuations
    originals as
    (
        select d.empid, d.code, d.[timestamp], d.duration
        from @data d
        left outer join continuations c on d.empid = c.empid and d.code = c.code and d.timestamp = c.timestamp
        where c.empid is null
    ),
    -- to hand the situation where we have more than one call for same agent and code, 
    -- find the next timestamp for each empid/code 
    nextcall as (
        select a.*, a2.[timestamp] nex
        from originals a
        outer apply (
            select top 1 [timestamp]
            from originals a2
            where a2.[timestamp] > a.[timestamp]
                and a.empid = a2.empid
                and a.code = a2.code
            order by a2.[timestamp] desc
        ) a2
    )
    select o.empid,
        o.code,
        dateadd(ss, -o.duration, o.timestamp) as [timestamp],
        o.duration + isnull(sum(c.duration),0) as duration
    from originals o
    left outer join nextcall n on o.empid = n.empid and o.code = n.code and o.[timestamp] = n.[timestamp] 
    left outer join continuations c on o.empid = c.empid
        and o.code = c.code
        -- filter the continuations on the range of times based on finding the next one
        and c.[timestamp] > o.[timestamp]
        and (n.nex is null or c.[timestamp] < n.nex) 
    group by o.empid,
        o.code,
        o.duration,
        o.[timestamp]