1 概述
在任何项目中,数据都扮演着至关重要的角色。而报表则是呈现和分析这些数据的关键工具。一个设计良好的报表不仅能够清晰地展示信息,还能为决策提供有力支持。因此,掌握报表设计的艺术对于数据分析师和项目管理者来说都是不可或缺的技能。
2 常见的报表类型
在日常工作和生活中,我们经常遇到各种类型的报表,它们按时间维度可以分为:
- 日报表
- 月报表
- 季报表
- 年度表
- 累计汇总表
每种报表都有其特定的用途和受众,选择合适的报表类型对于有效传达信息至关重要。
3 报表的基本构成
大多数报表的核心要素包括:
- 时间维度:几乎所有报表都会包含时间这一关键维度。
- 业务主体数据:反映特定业务指标或KPI的具体数据。
可以说,报表本质上是时间维度与业务主体数据的有机结合。这种结构使得用户能够清晰地看到业务指标随时间的变化趋势。
4 报表设计的重点考虑因素
4.1 数据量
在设计报表时,数据量是一个不容忽视的关键因素。良好的报表设计应该充分考虑到业务的实际数据量(即需要统计的业务记录数,可理解为数据表的行数)。根据数据量的大小,可能需要采取不同的设计策略和技术方案。
4.2 设计顺序
报表设计应遵循一定的顺序,通常建议按照时间范围从小到大进行设计:
- 日报表
- 月报表
- 季报表
- 年报表
- 汇总表
如果日数据量特别大(例如每日超过百万条记录),可能还需要考虑设计小时级别的报表。
4.3 数据依赖关系
不同层级的报表之间存在数据依赖关系:
- 汇总表 ← 年报表 ← 季报表 ← 月报表 ← 日报表 ← 实时统计数据
这种层级结构不仅有助于数据的逐级汇总,也便于进行数据校验和追溯。
5 报表设计的最佳实践
- 从小到大设计: 先设计最细粒度的明细报表,然后逐步设计更高层级的汇总报表。
- 考虑数据量: 根据实际业务数据量选择合适的统计粒度和展现方式。
- 保持一致性: 在不同层级的报表之间保持数据口径和计算逻辑的一致性。
- 注重可读性: 使用清晰的布局、恰当的图表类型和直观的数据可视化方法。
- 提供上下文: 加入同比、环比等对比数据,帮助用户更好地理解数据的意义。
- 考虑性能: 对于大数据量的报表,需要考虑查询性能和数据预聚合策略。
- 反馈迭代: 定期收集用户反馈,持续优化报表设计。
6 报表数据统计生成
根据对数据的要求可以使用定时任务是完成,也可以利用触发器,数据库的存储过程统计(维护更方便)。
基于springboot 定时任务 统计订单日报表的实例代码:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* 统计订单数据
* @author hua
* @Date: 2023/12/23 13:26
*/
@Component
@EnableScheduling
public class OrderDayJob {
@Autowired
ReportPlatformDayServiceImpl reportPlatformDayService;
@Autowired
SysJobRunLogServiceImpl sysJobRunLogService;
@Autowired
OrderDao orderDao;
final DateTimeFormatter DTF_DATE= DateTimeFormatter.ofPattern("yyyy-MM-dd");
final String JOB_NAME="OrderDayJob";
Logger log= LogManager.getLogger(OrderDayJob.class);
/**
* 每日订单统计
*/
@Scheduled(cron = "0 */1 * * * ?")
public void orderCalcJob() {
log.info("------------OrderDayJob------------begin");
SysJobRunLog sysJobRunLog=sysJobRunLogService.lambdaQuery()
.eq(SysJobRunLog::getJobName,JOB_NAME)
.orderByDesc(SysJobRunLog::getBusDate)
.last("limit 1").one();
//默认开始统计数据日期
String startDate="2023-12-01";
if(sysJobRunLog!=null){
startDate=sysJobRunLog.getBusDate();
}
LocalDate today=LocalDate.now();
//考虑最坏情况 如果因定时任务没有执行的,确保不占用系统过多资源 最多每次连续统计7天。
for(int i=0;i<7;i++){
LocalDate cur=LocalDate.parse(startDate,DTF_DATE);
if(cur.compareTo(today)==0){
calcOrderDayReport(startDate);
return;
}
LocalDate calcData= cur.plusDays(1);
startDate =calcData.format(DTF_DATE);
calcOrderDayReport(startDate);
}
log.info("------------OrderDayJob------------end");
}
/**
* 重算订单日报告
* @param startDate 开始日期
*/
@Transactional(rollbackFor = Exception.class)
public void calcOrderDayReport(String startDate) {
// 计算订单日期报告
List<ReportPlatformDay> reportPlatformDays = orderDao.calcOrderDayReport(startDate);
SysJobRunLog sysJobRunLog = new SysJobRunLog();
sysJobRunLog.setBeginTime(LocalDateTime.now());
//统计前删除数据
reportPlatformDayService.lambdaUpdate().eq(ReportPlatformDay::getOrderDay,startDate).remove();
// 如果报告列表不为空
if (!reportPlatformDays.isEmpty()) {
// 保存报告列表到数据订单日期服务
reportPlatformDayService.saveBatch(reportPlatformDays);
}
sysJobRunLog.setHandlerCount(reportPlatformDays.size());
sysJobRunLog.setJobName(JOB_NAME);
sysJobRunLog.setEndTime(LocalDateTime.now());
sysJobRunLog.setBusDate(startDate);
// 记录生成报表
sysJobRunLogService.save(sysJobRunLog);
}
}
上面的SysJobRunLog类除了记录报表定时任务运行情况,还可以选择性删除最后几天或者清空表使其重新计算日报表,表结构如下:
CREATE TABLE `sys_job_run_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_name` varchar(30) DEFAULT NULL COMMENT '定时器任务',
`begin_time` datetime DEFAULT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`handler_count` int(1) NOT NULL COMMENT '处理数据量',
`bus_date` date NOT NULL COMMENT '业务日期',
`remark` varchar(80) DEFAULT NULL COMMENT '定时任务运行过程中备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='定时器运行记录'
7 小结
通过遵循这些原则和最佳实践,我们可以设计出既能满足业务需求,又易于理解和使用的高质量报表。记住,优秀的报表设计不仅是一门科学,更是一门艺术,需要我们不断学习和实践。