云迈博客

您现在的位置是:首页 > 数据库 > MySQL > 正文

MySQL

MySQL 按月分组聚合最佳实践

wsinbol2021-12-18MySQL389
需求描述有一张带有时间字段的数据表,按月统计每个月的支出,并绘制最近一年或指定时间段数据的可视化图形。初始版本1.先确定起止时间$end_time=input('end_tim

需求描述

有一张带有时间字段的数据表,按月统计每个月的支出,并绘制最近一年或指定时间段数据的可视化图形。

初始版本

1.先确定起止时间


$end_time = input('end_time')?:date('Y-m-d');
$start_time  = date('Y-m-d',strtotime("-1 year", strtotime($end_time)));

2.MySQL分组


$total_money = Db::name('project')
->whereTime('start_time', 'between',[$start_time, $end_time])
->field("date_format(start_time, '%Y-%m') month, sum(project_money) as money")
->group("month")
->select();

问题分析

其实上面的代码是有问题的,尤其是第一个月的统计数据,会比实际值偏少。这是因为在第2步的执行查询时过滤掉了一部分数据。导致与直接使用条件查询时产生出入!

最佳实践

1.起止时间的优化


$end_time = input('end_time')?:date('Y-m-d');
if($end_time){
$end_time = date('Y-m-d', strtotime("last day of {$end_time}"));
}

$start_time = input('start_time')?:date('Y-m-d',strtotime('-1 year',strtotime($end_time)));
if($start_time){
$start_time = date('Y-m-d', strtotime("first day of {$start_time}"));
}

2.填充默认数据

这一步的主要工作是防止部分时间段在数据库中没有对应数据,导致生成的时间段不连续。

# 这个函数可以生成指定时间段内的时间数据,支持设置间隔、设置格式!
function periodDate($start_time,$end_time,$dis=1,$per='day',$format="Y-m-d"){
    $start_time = strtotime($start_time);
    $end_time = strtotime($end_time);
    $i=0;
    $arr = [];
    while ($start_time<=$end_time){
        $arr[$i]=date("$format",$start_time);
        $start_time = strtotime("+$dis $per",$start_time);
        $i++;
    }

    return $arr;
}

3.遍历数组


# 将核心数据转为以时间为key的字典结构

# 遍历时间段,填充核心数据
$date_arr = $this->periodDate($start_time, $end_time, 1, 'month','Y-m');

# 返回核心数据

总结

本文重点考察的是MySQL执行查询的流程,另外时间段的生成不能依赖数据库查询得出,防止数据库内的数据不连续导致生成的月份不连续!

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~