2009-01-30 4 views
7

я работал в телекоммуникационной компании несколько лет назад, и я должен был сформировать формулу, которая вычисляет продолжительность вызова по следующему алгоритму:Математическая формула для расчета длительности вызова

  • t1 является первый период
  • t2 является повторяющимся периодом
  • RCT является фактическим время вызова (в секундах)
  • диска является эффективной продолжительностью вызова (для выставления счетов)

, если RCT меньше t1, тогда CD равен t1
, если RCT больше t1, тогда CD = t1 + x * t2, где x будет «круглым» RCT до следующего максимального кратного t2.

Этот алгоритм переводится как: «Заряжайте в течение первых t1 секунд, затем заряжайте каждые t2 секунды после этого».

Пример:

t1 t2 RCT CD 
60 10 48 60 
60 10 65 70 
60 10 121 130 
30 20 25 30 
30 20 35 50 
30 20 65 70 

Вы можете создать функцию/SQL, который будет возвращать "продолжительность вызова" CD?

Без использования, если тогда еще ...?

ответ

2

EDIT: упрощенный и фиксированный < vs < = ошибка.

Нет плавающей точкой и работал на каждой базе данных у меня есть доступ к:

create table calls (t1 int, t2 int, rct int, cd int) 

insert into calls (t1, t2, rct, cd) 
values (60, 10, 48, 60) 

insert into calls (t1, t2, rct, cd) 
values (60, 10, 65, 70) 

insert into calls (t1, t2, rct, cd) 
values (60, 10, 121, 130) 

insert into calls (t1, t2, rct, cd) 
values (30, 20, 25, 30) 

insert into calls (t1, t2, rct, cd) 
values (30, 20, 35, 50) 

insert into calls (t1, t2, rct, cd) 
values (30, 20, 65, 70) 

--Additional test to show that it works 
insert into calls (t1, t2, rct, cd) 
values (60, 10, 70, 70) 

select t1, t2, rct, cd, 
t1 + case when rct <= t1 
    then 0 
    else ((rct-1-t1)/t2 + 1) * t2 end as CalceCD 
from calls 

Результат:

 
t1   t2   rct   cd   CalceCD 
----------- ----------- ----------- ----------- ----------- 
60   10   48   60   60 
60   10   65   70   70 
60   10   121   130   130 
30   20   25   30   30 
30   20   35   50   50 
30   20   65   70   70 
60   10   70   70   70 

(6 row(s) affected) 

Вы бы бесплатно создать функцию как UDF или независимо от вашего SQL среда позволяет для очистки выбора.

Редактировать: да, пол и смещение одного позволяют избежать плавающей математики.

+0

Это не должно быть 'потолок ((RCT -t1)/t2) 'вместо' (floor ((rct-t1)/t2) +1) '? В противном случае 60-10-70 создаст компакт-диск из 80. –

+0

Вставка в значения вызовов (60, 10, 70, 70) Вставка в значения звонков (60, 10, 80, 80) Это не работает –

+0

Эти вставки предполагают синтаксис, который может подразумевать формат таблицы. Добавьте (t1, t2, rct, cd), если необходимо. – Godeke

4

Предполагая, что ИНТ столбцы:

SELECT t1 
    ,t2 
    ,RCT 
    CASE 
    WHEN RCT < t1 
     THEN t1 
    ELSE 
     t1 + t2 * ((RCT - t1)/t2 + SIGN((RCT - t1) % t2)) 
    END AS CD 

Но я предполагаю, что есть еще один случай, позвольте мне увидеть, если я могу избавиться от него.

С только целочисленной арифметики (до сих пор не ANSI):

SELECT t1 
     ,t2 
     ,RCT 
     ,CD 
     ,t1 + SIGN(RCT/t1) * t2 * ((RCT - t1)/t2 + SIGN((RCT - t1) % t2)) AS CalcCD 
FROM Calls 
+0

Красивое решение! +1 –

+0

Спасибо, это все еще грязнее, чем я думаю, это может быть. С конверсией в float он чище, но я делаю ставку заметно медленнее для больших запросов (например, телефонных звонков!). –

+0

А хорошо. Нет необходимости в преждевременной оптимизации :) Если ОП в конечном итоге нуждается в его вычислении десяти миллиардов записей менее чем за секунду, ему придется опубликовать еще один вопрос о том, как повысить эффективность! –

2

Я хотел бы использовать:

t1 + t2*ceiling((rct - t1 + abs(rct - t1))*1.00/(2*t2)) 

Или:

t1 + t2*ceiling(Cast((rct - t1 + abs(rct - t1)) as float)/(2*t2)) 
+0

Вам не хватает открывающей скобки. –

+0

Спасибо, я только что заметил :) –

+0

Я попытался вставить его в несколько мест, но я не получаю результатов, которые соответствуют. –