将呼叫数据拆分为15分钟

时间:2011-03-24 09:12:33

标签: sql sql-server sql-server-2008

我在mssql 2008数据库中有一些电话呼叫数据,并希望将其拆分为15(或X)分钟间隔,以便在某些Erlang计算中使用。

调用logg:

call    start                   end
1       2011-01-01 12:00:01     2011-01-01 12:16:00
2       2011-01-01 12:14:00     2011-01-01 12:17:30
3       2011-01-01 12:29:30     2011-01-01 12:46:20

将显示为

call    start                   end                    
1       2011-01-01 12:00:01     2011-01-01 12:15:00    
1       2011-01-01 12:15:00     2011-01-01 12:16:00
2       2011-01-01 12:14:00     2011-01-01 12:15:00
2       2011-01-01 12:15:00     2011-01-01 12:17:30
3       2011-01-01 12:29:30     2011-01-01 12:30:00
3       2011-01-01 12:30:00     2011-01-01 12:45:00
3       2011-01-01 12:45:00     2011-01-01 12:46:20

有没有人对如何做到这一点有什么好的建议?

提前致谢

4 个答案:

答案 0 :(得分:3)

Richard是对的,这个查询将调用分成15分钟的时间间隔:

试试这个:

With CallData ([call],start,[end]) as 
(
select [call],start,case when [end]<=dateadd(minute,15,start) then [end] else dateadd(minute,15,start) end as [end] from CallLogTable
union all
select CallData.[call],CallData.[end],case when CallLogTable.[end]<=dateadd(minute,15,CallData.[end]) then CallLogTable.[end] else dateadd(minute,15,CallData.[end]) end as [end] from CallLogTable join CallData on CallLogTable.[call]=CallData.[call]
where CallData.[end]<case when CallLogTable.[end]<=dateadd(minute,15,CallData.[end]) then CallLogTable.[end] else dateadd(m,15,CallData.[end]) end
)
select * from CallData

不幸的是,我手头没有SQL,所以我无法测试它。然而,这是一个想法,所以你可能会设法调整它,以防它在某个地方失败。

我把别名和错误用m而不是分钟。你能试试看它是否有效。 TX。 (未完成测试时会发生这种情况)

要在15分钟(00/15/30/45)拆分它,你可以使用:

With CallData ([call],start,[end]) as 
(
select [call],start,case when [end]<=dateadd(minute,15*((datediff(minute,0,start)/15)+1),0) then [end] else dateadd(minute,15*((datediff(minute,0,start)/15)+1),0) end as [end] from CallLogTable
union all
select CallData.[call],CallData.[end],case when CallLogTable.[end]<=dateadd(minute,15*((datediff(minute,0,CallData.[End])/15)+1),0) then CallLogTable.[end] else dateadd(minute,15*((datediff(minute,0,CallData.[End])/15)+1),0) end as [end] from CallLogTable join CallData on CallLogTable.[call]=CallData.[call]
where CallData.[end]<case when CallLogTable.[end]<=dateadd(minute,15*((datediff(minute,0,CallData.[End])/15)+1),0) then CallLogTable.[end] else dateadd(minute,15*((datediff(minute,0,CallData.[End])/15)+1),0) end
)
select * from CallData order by [call],start

答案 1 :(得分:3)

样本表

create table CallLogTable (call int, start datetime, [end] datetime)
insert CallLogTable select
1, '2011-01-01 12:00:01', '2011-01-01 12:16:00' union all select
2, '2011-01-01 12:14:00', '2011-01-01 12:17:30' union all select
3, '2011-01-01 12:29:30', '2011-01-01 12:46:20'

查询

select
    call,
    case when st < start then start else st end [start],
    case when et > [end] then [end] else et end [end]
from (select *,
             xstart = dateadd(mi, 15*(datediff(mi, 0, d.start)/15), 0),
             blocks = datediff(mi, d.[start], d.[end])/15+2
      from CallLogTable d) d
cross apply (
    select
           st = dateadd(mi,v.number*15,xstart),
           et = dateadd(mi,v.number*15+15,xstart)
    from master..spt_values v
    where v.type='P' and v.number <= d.blocks
      and d.[end] > dateadd(mi,v.number*15,xstart)) v
order by call, start

如果要创建此查询的视图,请删除最后一个[order by]行

注释

  1. 表达式(xstart)dateadd(mi, 15*(datediff(mi, 0, d.start)/15), 0)计算呼叫开始的15分钟边框
  2. 块被预先计算为快速截止,以便不处理超出spt_values所需的行数
  3. cross apply允许在子查询中使用先前表中的每一行。子查询构建每个15分钟的块,涵盖期间
  4. case语句将开始和结束时间与实际值对齐,如果这些是在15分钟的边界内

答案 2 :(得分:0)

一天只有1440分钟。因此,您可以创建并填充1440行MINUTES表,其主键是一个四位数字,表示24小时格式的小时分钟(例如,下午9:13将是2113)。然后,您可以在该表中包含尽可能多的列,以表示当天的任何一分钟:它所属的四分之一小时,是否被视为非高峰或高峰,其计费率在计划A下是什么,等等上。您只需根据用例需要添加列。完全可扩展。

在您的示例中,第一列MINUTES.QuarterHour将指示分钟落入哪个季度小时。例如,02:17是在季度小时6。填充表后,您只需使用HHMMChunk = MINUTES上的简单连接,即可使用电话呼叫表中日期时间值的HHMM块来回退该时间所属的四分之一小时。 ID。优点:查询更简单,更易于编写和维护,并且可能没有计算密集型。

编辑:该方法也是通用的和可移植的(即不是特定于实现的)。

答案 3 :(得分:0)

引人入胜的问题!

仅仅是为了踢,这是一个PostgreSQL方法,使用generate_sequence()来填充内部15分钟的间隔。毫无疑问,这是建立第一个和最后一个区间的前两个联盟的合并方式,但这仍然是读者的练习。

select
     c.call
    ,c.dt_start - date_trunc('day', c.dt_start) as "begin"
    ,(date_trunc('second', (cast (c.dt_start - date_trunc('day', c.dt_start) as interval)
        / (15*60) + interval '1 second'))) * (15*60) as "end"
from
    call c
where
    (date_trunc('second', (cast (c.dt_start - date_trunc('day', c.dt_start) as interval)
        / (15*60) + interval '1 second'))) * (15*60)
    <= date_trunc('second', (cast (c.dt_end - date_trunc('day', c.dt_end) as interval)
        / (15*60))) * (15*60)
union select
    c.call
    ,greatest(
        c.dt_start - date_trunc('day', c.dt_start),
        date_trunc('second', (cast (c.dt_end - date_trunc('day', c.dt_end) as interval)
            / (15*60))) * (15*60)
    ) as "t_last_q"
    ,c.dt_end - date_trunc('day', c.dt_end) as "t_end"
from
    call c
union select TQ.call, TQ.t_next_q, SEQ.SLICE
from
    (select cast(g || ' seconds' as interval) as SLICE
         from generate_series(0, 86400, 15*60) g) SEQ,
    (select
         c.call
        ,(date_trunc('second', (cast (c.dt_start - date_trunc('day', c.dt_start) as interval)
            / (15*60) + interval '1 second'))) * (15*60) as "t_next_q"
        ,date_trunc('second', (cast (c.dt_end - date_trunc('day', c.dt_end) as interval)
            / (15*60))) * (15*60) as "t_last_q"
    from
        call c
    ) TQ
where
       SEQ.SLICE >  TQ.t_next_q
   and SEQ.SLICE <= TQ.t_last_q