现有一个业务数据表栏目大概如下所示:
id int 记录id group_id int 分组id income int 收入 expense int 开支 month_date date 月份时间,例如:2019-12-01 week int 第几周
我要实现的是获取某小组在任意时间范围之间的收入、开支及利润统计。
由于数据是按某月第几周的方式来新增的,而筛选的时间选择是年-月-日的方式,所以筛选时间的条件必须先由年-月-日格式转为某月几周的形式。这个转换过程本文就不讲述了。
我们就直接看,两个某月某周格式的时间范围,统计是如何实现的。
用的是laravel框架,本人一开始写的代码如下:
$startMonth = '2019-11-01'; $startWeek = 2; $endMonth = '2019-12-01'; $endWeek = 2; $query = Finance::where(function($outQuery) use($startMonth, $startWeek, $endMonth, $endWeek){ $outQuery->orWhere(function($query) use($startMonth, $startWeek){ $query->where('month_date', $startMonth) ->where('week', '>=', $startWeek); }) ->orWhere(function($query) use($startMonth, $endMonth){ $query->where('month_date', '>', $startMonth) ->where('month_date', '<', $endMonth); }) ->orWhere(function($query) use($$endMonth, $endWeek){ $query->where('month_date', $endMonth) ->where('week', '<=', $endWeek); }); });
上面代码逻辑有漏洞,你能看出来吗?
将上面代码转换成sql语句,如下:
select * from zhai14_cost where group_id = ? and ( (date_time = ? and week >= ?) or (date_time > ? and date_time < ?) or (date_time=? and week <=?) )
你还能看出来问题吗?
特殊情形是,当开始时间和结束都是同一个月同一周的时候,应该实现的功能就是查询那一个月那一周的数据。但是上面代码并不能达到这一目的。
为了方便分析,我们假定时间都是11月的第3周。
将数值代入到上面sql语句中去,得到如下:
(date_time = '2019-11-01' and week >= 3) or (date_time > '2019-11-01' and date_time < '2019-11-01') or (date_time='2019-11-01' and week <=3)
中间一行是空区间,就可以忽略了。
剩下第一行和第三行所形成的范围就成了2019-11-01这整个月的时间了,而实际应该就只是2019年11月的第3周这一周的时间而已。
这就是上面代码的漏洞所在。
修补方法就是将开始时间和结束时间相等的情形考虑进去,最终代码如下所示:
if( $startMonth == $endMonth ){ if( $startWeek == $endWeek ){ $query = Finance::where('month_date', $startMonth) ->where('week', $startWeek); }else{ $query = Finance::where('month_date', $startMonth) ->where('week', '>=', $startWeek) ->where('week', '<=', $endWeek); } }else{ $query = Finance::where(function($outQuery) use($startMonth, $startWeek, $endMonth, $endWeek){ $outQuery->orWhere(function($query) use($startMonth, $startWeek){ $query->where('month_date', $startMonth) ->where('week', '>=', $startWeek); }) ->orWhere(function($query) use($startMonth, $endMonth){ $query->where('month_date', '>', $startMonth) ->where('month_date', '<', $endMonth); }) ->orWhere(function($query) use($$endMonth, $endWeek){ $query->where('month_date', $endMonth) ->where('week', '<=', $endWeek); }); }); }
本文是翟码农个人博客蓝翟红尘里php分类下的文章,转载请注明出处:http://www.zhai14.com/blog/fcece0fe04e1951cc7731de3a13ddb07.html