绿色的部分是不用扣除的,黄色的部分是需要扣除掉的。把问题统一在一起,所有的奖金总数总体分为两个部分,一部分在绿色的部分之中,一部分在黄色部分之中。分别讨论这两种情况,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_numisnull 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))