B站视频里的营业额统计是通过日期循环查询对应的金额,这样会执行多查询,对数据库压力过大。
这里可以使用GROUP BY实现。
<select id="getTurnoverStatistics" resultType="java.util.Map">
SELECT
DATE(order_time) as orderDate,
IFNULL(SUM(amount), 0) as turnover
FROM orders
WHERE status = 5
AND DATE(order_time) BETWEEN #{beginDate} AND #{endDate}
GROUP BY DATE(order_time)
ORDER BY orderDate
</select>
查询结果如下
具体实现方法:
public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
log.info("查询营业额统计,开始日期:{},结束日期:{}", begin, end);
// 1. 生成日期列表(使用Stream API优化)
List<LocalDate> dateList = begin.datesUntil(end.plusDays(1))
.collect(Collectors.toList());
// 2. 查询数据库获取营业额数据
List<Map<String, Object>> turnoverData = orderMapper.getTurnoverStatistics(begin, end);
// 3. 将数据库结果转换为Map便于查找
Map<LocalDate, BigDecimal> turnoverMap = turnoverData.stream()
.collect(Collectors.toMap(
data -> ((java.sql.Date) data.get("orderDate")).toLocalDate(),
data -> (BigDecimal) data.get("turnover")
));
// 4. 组装完整的日期和营业额列表(处理缺失日期)
String dateListStr = dateList.stream()
.map(date -> date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.collect(Collectors.joining(","));
String turnoverListStr = dateList.stream()
.map(date -> turnoverMap.getOrDefault(date, BigDecimal.ZERO).toString())
.collect(Collectors.joining(","));
log.info("营业额统计完成,共{}天数据", dateList.size());
// 5. 构建返回对象
return TurnoverReportVO.builder()
.dateList(dateListStr)
.turnoverList(turnoverListStr)
.build();
}