Разделить данные вызова на 15-минутные интервалы - PullRequest
1 голос
/ 24 марта 2011

У меня есть некоторые данные телефонных звонков в базе данных mssql 2008, и я хотел бы разделить их на 15 (или X) минутных интервалов, чтобы использовать их в некоторых вычислениях Эрланга.

журнал вызовов:

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 ]

3 голосов
/ 24 марта 2011

Пример таблицы

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. , перекрестное применение позволяет использовать каждую строку в предыдущей таблице в подзапросе.подзапрос строится каждый 15-минутный блок, охватывающий период
  4. , операторы case выравнивают время начала и окончания с фактическими, если они находятся внутри 15-минутных границ
3 голосов
/ 24 марта 2011

Ричард прав, этот запрос разбивает вызовы на 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
0 голосов
/ 24 марта 2011

Увлекательная задача!

Просто для целей, вот подход 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
0 голосов
/ 24 марта 2011

В день всего 1440 минут. Таким образом, вы можете создать и заполнить 1440 строками таблицу MINUTES, первичным ключом которой является четырехзначное число, представляющее часы-минуты в 24-часовом формате (например, 21:13 будет 2113). Тогда у вас может быть столько столбцов в этой таблице, сколько нужно для характеристики любой минуты дня: в какой четверть часа он попадает, считается ли он непиковым или пиковым, какова его тарифная ставка в соответствии с планом А, и т. Д. на. Вы просто продолжаете добавлять столбцы, как того требуют ваши варианты использования. Полностью расширяемый.

В вашем примере первый столбец MINUTES.QuarterHour будет указывать, на какой четверть часа пришла минута. 02:17 в четверть часа 6, например. Как только таблица заполнится, все, что вам нужно сделать, - это использовать блок ЧЧММ вашего значения datetime из таблицы телефонных вызовов, чтобы отозвать четверть часа, к которому относится это время, используя простое соединение HHMMChunk = MINUTES. Я бы. Преимущества: запросы гораздо проще и проще в написании и обслуживании, и они, вероятно, не так требовательны к вычислительным ресурсам.

РЕДАКТИРОВАТЬ: подход также является универсальным и переносимым (т.е. не зависящим от реализации).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...