绿色的部分是不用扣除的,黄色的部分是需要扣除掉的。把问题统一在一起,所有的奖金总数总体分为两个部分,一部分在绿色的部分之中,一部分在黄色部分之中。分别讨论这两种情况,1,如果奖金总数落在绿色的范围之中,则需要扣除的奖金的总数(A1)为重复消费的次数(repeat_num)乘于400,而本次结算需要扣除的奖金金额为需要扣除的奖金的总数(A1)减去以前扣除的奖金的总数。2,如果奖金总数落在黄色的范围之中,则需要扣除的奖金总数不仅包括重复消费次数(repeat_num)乘于400,而且还包括部分黄色部分,而这些黄色部分的可以这样计算得到:奖金总数(total_award)减去重复消费次数(repeat_num)乘以4000,再减去3600,即得到部分黄色区域的金额。把需要扣除的金额加起来(A2),减去已经扣除的金额总和就是本次结算需要扣除的奖金金额。
基于上述分析,算法分为两个部分,一个部分用于计算重复消费,相应的Sql语句为
while exists(select 1 from member where total_award>=(repeat_num+1)*4000)
begin
insert into award_repeat(turns,days,m_ID,award_type)
select @turns,@days,m_ID,0
from member
where total_award>=(repeat_num+1)*4000
--记录重复消费,以便于公司送产品
update member
set repeat_num=repeat_num+1
where total_award>=(repeat_num+1)*4000
--更新计算的结果,并进入循环
end
由于采用逐步增加Repeat_num的方法,每次计算重复消费之后更新重复消费的次数,经过有限次计算之后,循环结束,程序不会陷入死循环。
算法的第二部分实现分为两种情况,分别实现如下:(AwardRepeat为视图,数据来自award_day表,视图的内容为员工编号m_id和相应编号扣除的奖金总和,由于一些员工没有扣除过奖金,需要使用外连接来确保完整性)
第一种情况:奖金总额落在绿色部分
if exists(select 1 from member where total_award between 4000*repeat_num and 4000*repeat_num+3600)
begin
insertintoaward_day(turns,days,m_ID,award_num)
--批量的一次性插入需要扣除的奖金纪录
select @turns,@days,member.m_ID,(-1)*(400*repeat_num /*(A1)*/
+(case when award_numis
null then 0 else award_num end))
from member left join awardRepeaton(member.m_ID=awardRepeat.m_ID)
where total_award between 4000*repeat_num + 1 and 4000*repeat_num+3600
and(-1)*(400*repeat_num+(case when award_numis null then 0 else award_num end))<0
--确保扣除金额为0的纪录不被插入
end
第二种情况:奖金总额落在黄色部分
if exists( select 1 from member where total_award between 4000*repeat_num+3600+1 and 4000*(repeat_num+1))
begin
insert into award_day(turns,days,m_ID,award_num)
select @turns, @days, member.m_ID,(-1)*(400*repeat_num + total_award-4000 * repeat_num-3600 /*A2*/
+(case when award_numis null then 0 else award_num end))
from member left join awardRepeaton(member.m_ID=awardRepeat.m_ID)
where total_award between 4000*repeat_num +3600+1and 4000*(repeat_num+1)
and(-1)*(400*repeat_num + total_award -4000* repeat_num-3600+(case when award_numis null then 0 else award_numend))<0
--确保扣除金额为0的纪录不被插入
end
实验结果:(award_day)表的一部分
award_day_id
|
turns
|
days
|
m_ID
|
award_num
|
181
|
5
|
13
|
m000000000
|
-20
|
199
|
6
|
16
|
m000000000
|
-380
|
252
|
9
|
25
|
m000000000
|
-330
|
305
|
10
|
28
|
m000000000
|
-70
|
332
|
11
|
31
|
m000000000
|
-400
|
415
|
15
|
45
|
m000000000
|
-800
|
图(2)
结论:在数据库中研究和实现算法有着相当大的困难,同时也是一种挑战。随着现实世界中业务规则的日益复杂,相应的数据库应用软件实现业务规则需要的算法也日益复杂,把复杂的算法应用在数据库中需要找到一个统一的方式,在熟悉业务规则的前提下,根据数据库的特点和相应的执行命令的能力,找到一种适合数据库批量计算的步骤是解决问题的关键。