天天看点

sql 求模 实现 贪婪算法

背景:

  最近在维护一个项目, 因新功能需求拓展.  有一个字段存储 一个星期中的几天,可能是全部,也有可能只是其中的星期一, 星期三,等.

 因为项目中有一个枚举值, 已作好初始化赋值工作, 而且 客户端开发时直接把组合值合并成一个早已存入这个字段到DB.

 我在项目别的地方(动态批量生成月报表时,又需要得到这个具体的频率值. 因为每个月有几个星期一,星期三,不是固定的, 需要动态计算.),  所以, 又需要将其还原为 其中具体对应的 星期一,星期三 等. 这里就需要对这个组合值,进行求模操作. 于是便有了本文.

运行环境: sql server 2014

测试环境: sql server 2005

求模结果:   请见 ActualMapping 列对应的值

eg1: 1025 = 1024 * 1 + 1

sql 求模 实现 贪婪算法

eg2:  1552 = 1024 * 1 + 512 * 1 + 16 * 1

     我们数据库中,有条记录,某个字段值存的就是1552, 表示频率取 每周五,每周六,每周日各一次

sql 求模 实现 贪婪算法

sql脚本:

declare @total bigint

set @total=1552
--55451121212121
--784546
--2558=1024*2 + 256*1 + 128 * 1 + 64 * 1 + 32 * 1 + 16 * 1 + 1 * 14
--1552= 1024*1 + 512 * 1 + 16*1
--1553= 1024*1 + 512 * 1 + 16*1 + 1 * 1
-- 1554 = 1024*1 + 512 * 1 + 16*1 + 1 * 2
-- 1025 = 1024* 1 + 1 * 1
 
declare @tblRecurrenceType table
(
 [DayName] varchar(20),
 [DayValue] bigint,
 [ActualMapping] bigint default (0),
 ID bigint identity
)
 

insert into @tblRecurrenceType
(
   [DayName],
   [DayValue]
)
select 'EverySaturday',1024
--union all select 'EveryWorkday',992
union all select 'EveryFriday',512
union all select 'EveryThursday',256
union all select 'EveryWednesday',128
union all select 'EveryTuesday',64
union all select 'EveryMonday',32
union all select 'EverySunday',16
union all select 'UNknown',1

--select  * from @tblRecurrenceType


declare @iTime bigint 
  set @iTime=0;
declare @tmpDayValue bigint
  set @tmpDayValue=0
declare @tmpActualMapping bigint
  set @tmpActualMapping=0

declare @iTblRowCount bigint
  SET @iTblRowCount=0
 SELECT @iTblRowCount=count(*) from @tblRecurrenceType

while @total>0
begin
   set @iTime=@iTime+1;
      
   select @tmpDayValue=DayValue from @tblRecurrenceType where ID=@iTime
     
      if(@total<@tmpDayValue)
      begin
            if(@iTime=@iTblRowCount)
            begin
        update @tblRecurrenceType set ActualMapping=@total
        from @tblRecurrenceType where [DayValue]<=@total
            end
            else
            begin
        update @tblRecurrenceType set ActualMapping=1
        from @tblRecurrenceType where [DayValue]=@total
            end

            continue
      end 
      else
      begin
      set @tmpActualMapping=@total / @tmpDayValue
      if(@tmpActualMapping>0)
      begin
        update @tblRecurrenceType set ActualMapping=@tmpActualMapping
        from @tblRecurrenceType where [DayValue]=@tmpDayValue
               
        set @total = @total % @tmpDayValue 
      end
      else
      begin
         update @tblRecurrenceType set ActualMapping=1
         from @tblRecurrenceType where [DayValue]=@total
    
        set @total = @total - @tmpDayValue 
           
        if(@total<0)
         break
      end
     end
 
end

--select @iTime  -- running times
select * from @tblRecurrenceType  -- get those ActualMapping
select * from @tblRecurrenceType  where ActualMapping>0 -- get those ActualMapping      

备注:

    本来,可以写得相对简单一些. 但完成我需要的功能后. 发现这其实就是一个贪婪算法的实现. 想起了N久前某位老师提到的售票员找零问题, 于是, 便有了上面的sql脚本.