2009-01-30 16 views
7

stavo lavorando per una società di telecomunicazioni qualche anno fa e ho dovuto generare una formula che calcola la durata di una chiamata secondo il seguente algoritmo:formula matematica per il calcolo della durata delle chiamate

  • t1 è il primo periodo
  • t2 è il periodo ricorrente
  • RCT è il tempo effettivo di chiamata (in secondi)
  • CD è la durata della chiamata efficace (ai fini della fatturazione)

se RCT è minore di t1, allora il CD è uguale a t1
se RCT è maggiore di t1, quindi CD = t1 + x * t2, dove x "arrotonda" RCT al successivo multiplo più alto di t2.

Questo algoritmo si traduce in: "Carica per i primi t1 secondi, quindi carica ogni t2 secondi dopo quello".

Esempio:

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 

Si può creare una funzione/SQL che restituirà la "durata della chiamata" CD?

Senza usare se poi altro ...?

risposta

2

MODIFICA: semplificata ulteriormente e fissa < rispetto a < = errore.

No virgola mobile e lavorato su tutti i database ho accesso 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 

Risultato:

 
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) 

Si sarebbe libero di creare la funzione come una funzione definita dall'utente o qualunque sia il vostro ambiente SQL consente per pulire la selezione.

Modifica: sì, il pavimento e uno scostamento di uno evitano la matematica flottante.

+0

Non dovrebbe essere 'soffitto ((RCT -t1)/t2) 'invece di' (floor ((rct-t1)/t2) +1) '? In caso contrario, 60-10-70 produrrebbe un CD di 80. –

+0

inserire i valori delle chiamate (60, 10, 70, 70) inserire i valori delle chiamate (60, 10, 80, 80) Questi non funzionano –

+0

Questi inserti presuppongono una sintassi che può implicare il formato della tabella. Aggiungi il (t1, t2, rct, cd) se necessario. – Godeke

4

Assumendo colonne int:

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

Ma credo che ci sia ancora un caso, fammi vedere se riesco a sbarazzarsi di esso.

Con solo aritmetica intera (ancora non ANSI):

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

Bella soluzione! +1 –

+0

Grazie, è ancora più caotico di quanto penso possa essere. Con la conversione a fluttuare è più pulito, ma scommetto molto più lentamente per le query BIG (come le telefonate!). –

+0

Ah bene. Nessuna necessità di ottimizzazione prematura :) Se l'OP finisce per aver bisogno di calcolare dieci miliardi di voci in meno di un secondo, dovrà postare un'altra domanda su come migliorare l'efficienza! –

2

userei:

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

Oppure:

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

Ti manca una parentesi aperta. –

+0

Grazie, ho appena notato :) –

+0

Ho provato a inserirne uno in alcuni punti, ma non sto ottenendo risultati corrispondenti. –

Problemi correlati