7

几年前我在一家电信公司工作,我不得不根据以下算法生成一个计算通话时长的公式:

  • t1 是第一个时期
  • t2 是循环周期
  • RCT 是实际通话时间(以秒为单位)
  • CD 是有效通话时长(用于计费目的)

如果 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吗?

不使用 if then else ...?

4

3 回答 3

4

假设 int 列:

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

但我猜还有一个CASE,让我看看能不能摆脱它。

仅使用整数算术(仍然不是 ANSI):

SELECT  t1
       ,t2
       ,RCT
       ,CD
       ,t1 + SIGN(RCT / t1) * t2 * ((RCT - t1) / t2 + SIGN((RCT - t1) % t2)) AS CalcCD
FROM    Calls
于 2009-01-30T22:18:22.940 回答
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) )
于 2009-01-30T22:38:31.633 回答
2

编辑:进一步简化,并修复 < 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 行受影响)

您可以自由地将函数创建为 UDF 或 SQL 环境允许清理选择的任何内容。

编辑:是的,地板和一个偏移量避免了浮动数学。

于 2009-01-30T22:10:34.873 回答