2009-01-30 9 views
7

yo estaba trabajando para una empresa de telecomunicaciones hace algunos años y que tenían que generar una fórmula que calcula la duración de una llamada de acuerdo con el siguiente algoritmo:Fórmula matemática para el cálculo de la duración de llamada

  • t1 es el primer período
  • t2 es el periodo recurrente
  • ECA es el tiempo de llamada real (en segundos)
  • CD es la duración de la llamada efectiva (para fines de facturación)

si RCT es menor que t1, entonces el CD es igual a t1
si RCT es mayor que t1, luego CD = t1 + x * t2, donde x "redondeará" RCT al siguiente múltiplo más alto de t2.

Este algoritmo se traduce en: "Cargue durante los primeros t1 segundos, luego cargue cada t2 segundos después de eso".

Ejemplo:

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 

Se puede crear una función/SQL que devuelva la "duración de la llamada" CD?

Sin usar si entonces else ...?

Respuesta

2

EDITAR: simplificado aún más, y < fijo contra < = error.

No coma flotante y trabajado en cada base de datos que tengo acceso a:

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 

Resultado:

 
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) 

serías libre para crear la función como una UDF o lo que su entorno de SQL permite para limpiar el seleccionar.

Editar: sí, el piso y un desplazamiento de uno evita las matemáticas flotantes.

+0

¿No debería ser 'techo ((ECA -t1)/t2) 'en lugar de' (piso ((rct-t1)/t2) +1) '? De lo contrario, 60-10-70 produciría un CD de 80. –

+0

inserte en valores de llamadas (60, 10, 70, 70) inserte en valores de llamadas (60, 10, 80, 80) Estos no funcionan –

+0

Esos insertos suponen una sintaxis que puede implicar el formato de la tabla. Agregue el (t1, t2, rct, cd) si es necesario. – Godeke

4

Suponiendo columnas INT:

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

Pero creo que todavía hay un caso, vamos a ver si lo puedo deshacerme de él.

Con la aritmética sólo números enteros (todavía no ANSI):

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

¡Hermosa solución! +1 –

+0

Gracias, todavía es más complicado de lo que creo que puede ser. Con la conversión a flotación, es más limpio, pero apostaría mucho más lento para consultas GRANDES (¡como llamadas telefónicas!). –

+0

Ah bien. No hay necesidad de una optimización prematura :) Si el OP termina necesitándolo para calcular diez mil millones de entradas en menos de un segundo, tendrá que publicar otra pregunta sobre cómo mejorar la eficiencia. –

2

me gustaría utilizar:

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

O:

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

Falta un paréntesis de apertura. –

+0

Gracias, acabo de notar :) –

+0

Intenté poner uno en algunos lugares, pero no estoy obteniendo resultados que coincidan. –

Cuestiones relacionadas