大家好,欢迎来到IT知识分享网。
前言
最近小编在项目中遇到需要查询某个工单还有多少剩余处理时间的需求,并且要按照工作时的计算方式,对剩余处理时间按升序排列,如果是对查询出来的工单进行剩余时间计算,那么在程序中就能够完成,但偏偏要求需要进行排序,这可就难了,因为数据表内记录超过百万,放在程序中处理肯定会溢出,最终还是选择加个mysql函数,让数据库帮忙处理,但找遍各大论坛也没有找到在mysql中计算工作时的方法,无奈只能自己来写个,在这里分享给大家!
不说废话,直接上代码!
说明
这里要说明一下函数中使用的 frame_workingday 这个表,这是一张日历表,记录了哪天是工作日,跟百度搜索的万年历一样的


表结构
完整代码
drop function if exists getworkminute; create function getworkminute(starttime datetime, endtime datetime) returns integer begin -- 声明变量 -- -- 最终结果 declare interval_minute integer default 0; -- 开始时间是否工作日 declare startiswork integer default 0; -- 结束时间是否工作日 declare endiswork integer default 0; -- 开始时间与结束时间之间的工作日天数,包含自身 declare workdaynum integer default 0; -- 定义上午、下午 上下班时间 -- set @monworkstart = '08:00:00'; set @monworkend = '12:00:00'; set @noonworkstart = '14:00:00'; set @noonworkend = '18:00:00'; set @startdate = date_format(starttime,'%Y-%m-%d'); set @enddate = date_format(endtime,'%Y-%m-%d'); set @timestart = date_format(starttime, '%H:%i:%s'); set @timeend = date_format(endtime, '%H:%i:%s'); -- 查询 select count((@startdate = wdate and isworkingday = 1) or null) , count((@enddate = wdate and isworkingday = 1) or null) , count(isworkingday = 1 or null) into startiswork,endiswork,workdaynum from frame_workingday where wdate between @startdate and @enddate; -- 如果开始和结束时间是同一天,且是工作日 if @startdate = @enddate and startiswork = 1 and endiswork = 1 then set workdaynum = 0; -- 开始时间小于上午上班时间 if @timestart < @monworkstart then -- 结束时间处于上午工作时间,计算 上午上班时间与结束时间间隔 if @timeend > @monworkstart and @timeend < @monworkend then set interval_minute = interval_minute + timestampdiff(minute, concat(@startdate,' ',@monworkstart), concat(@startdate,' ', @timeend)); -- 结束时间处于午休时间,计算 半天 elseif @timeend >= @monworkend and @timeend <= @noonworkstart then set interval_minute = interval_minute + 240; -- 结束时间处于下午工作时间,计算 半天+下午上班时间与结束时间间隔 elseif @timeend >= @noonworkstart and @timeend <= @noonworkend then set interval_minute = interval_minute + 240 + timestampdiff(minute, concat(@startdate,' ',@noonworkstart), concat(@startdate,' ', @timeend)); -- 结束时间大于下午下班时间,计算 一天 elseif @timeend >= @noonworkend then set interval_minute = interval_minute + 480; end if; -- 开始时间小于上午下班时间 elseif @timestart < @monworkend then -- 结束时间小于上午下班时间,计算 开始时间与结束时间间隔 if @timeend < @monworkend then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @timeend)); -- 结束时间是午休时间,计算 开始时间与上午下班时间间隔 elseif @timeend >= @monworkend and @timeend <= @noonworkstart then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)); -- 结束时间在下午工作时间,计算 开始时间与上午下班时间间隔+下午上班时间与结束时间间隔 elseif @timeend >= @noonworkstart and @timeend <= @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)) + timestampdiff(minute, concat(@startdate,' ',@noonworkstart), concat(@startdate,' ', @timeend)); -- 结束时间大于下午下班时间 计算 开始时间与上午下班时间间隔+半天 elseif @timeend>= @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)) + 240; end if; -- 开始时间小于下午上班时间,即处于午休时间 elseif @timestart < @noonworkstart then -- 结束时间小于下午上班时间,计算 0 if @timeend < @noonworkstart then set interval_minute = interval_minute + 0; -- 结束时间在下午工作时间,计算 下午上班时间与结束时间间隔 elseif @timeend >= @noonworkstart and @timeend <= @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, concat(@startdate,' ',@noonworkstart), concat(@startdate,' ', @timeend)); -- 结束时间大于下午下班时间 计算 半天 elseif @timeend>= @noonworkend then set interval_minute = interval_minute + 240; end if; -- 开始时间小于下午下班时间 elseif @timestart < @noonworkend then -- 结束时间小于下午下班时间,计算 开始时间与结束时间间隔 if @timeend < @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, concat(@startdate,' ',@timestart), concat(@startdate,' ', @timeend)); -- 结束时间大于下午下班时间,计算 开始时间与下午下班时间间隔 elseif @timeend >= @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, concat(@startdate,' ',@timestart), concat(@startdate,' ', @noonworkend)); end if; end if; else -- 不是同一天的情况 if startiswork = 1 then -- 工作日减去1天 set workdaynum = workdaynum - 1; -- 小于上午上班时间,计算 一天 if @timestart <= @monworkstart then set interval_minute = interval_minute + 480; -- 处于上午工作时间,计算 开始时间与上午下班时间间隔+半天 elseif @timestart <= @monworkend then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)) + 240; -- 处于午休区间,计算 半天 elseif @timestart <= @noonworkstart then set interval_minute = interval_minute + 240; -- 处于下午工作时间,计算 开始时间与下午下班时间间隔 elseif @timestart <= @noonworkend then set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @noonworkend)); end if; end if; if endiswork = 1 then -- 工作日减去1天 set workdaynum = workdaynum - 1; -- 小于上午上班时间,计算 0 if @timeend <= @monworkstart then set interval_minute = interval_minute + 0; -- 处于上午工作时间,计算 上午上班时间与结束时间间隔 elseif @timeend <= @monworkend then set interval_minute = interval_minute + timestampdiff(minute, concat(@enddate,' ', @monworkstart), endtime); -- 处于午休时间,计算 半天 elseif @timeend <= @noonworkstart then set interval_minute = interval_minute + 240; -- 处于下午工作时间,计算 半天+下午上班时间与结束时间间隔 elseif @timeend <= @noonworkend then set interval_minute = interval_minute +240 + timestampdiff(minute, concat(@enddate,' ', @noonworkstart), endtime); -- 大于下午下班时间,计算 一天 elseif @timeend > @noonworkend then set interval_minute = interval_minute + 480; end if; end if; end if; -- 计算得到最终的工作分钟数 return interval_minute + workdaynum * 480; end;
效果检查
我们使用4月的日历进行测试,测试结果如下:

性能检查
实测5万5千条记录,耗时1分10秒,当然这是在本机docker上的mysql跑的结果,本机的配置比较低,CPU为i5-8250U,mysql最大内存1G
结束语
函数在数据量少的情况下还是可以使用,多了就会占用宝贵的数据库资源,得不偿失,如果大家有更好的办法,欢迎留言讨论!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/181292.html