首先,我们要知道,其实LambdaQueryWrapper是无法使用sum聚合函数的,因为LambdaQueryWrapper的select()方法无法传入字符串,但你有张良计,我有过墙梯,我们其实可以迂回来做。

先使用QueryWrapper,拼接我们需要的select,然后再转成LambdaQueryWrapper,具体如下:

order对象:(简单写需要的东西)

@Data
@TableName("t_order")
public class OrderModel {
	/**
     * 商户号
     */
	private String merNo;
	/**
     * 订单号
     */
	private BigDecimal orderId;
 	/**
     * 手续费
     */
	private BigDecimal feeAmt;
	/**
     * 到账金额
     */
	private BigDecimal arrivalAmt;
	/**
     * 交易时间
     */
	private LocalDate tradeDate;
}

代码如下:

Page<OrderModel> page = orderService.page(new Page<>(1, 20), new QueryWrapper<OrderModel>()
	.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ")
	.lambda()
	.between(StrUtil.isNotBlank(commandReq.getStartDate()) && StrUtil.isNotBlank(commandReq.getEndDate()),
                        OrderModel::getTradeDate,
                		StrUtil.isNotBlank(startDateStr) ? LocalDate.parse(startDateStr) : null,
                		StrUtil.isNotBlank(endDateStr) ? LocalDate.parse(cendDateStr) : null)  
    .groupBy(OrderModel::getMerNo));

分页查询,按照商户号进行分组,手续费和到账金额进行汇总,如果时间不为空,用between范围查询。
先用QueryWrapper处理掉聚合函数,然后再用.lambda()转成LambdaQueryWrapper,保证下面能用lambda写法。
SUM(fee_amt)直接丢在fee_amt里,就不用去新加属性了,如果不想,可以再加个对象里补个汇总字段。

@TableField(exist = false)
private BigDecimal FeeTotalAmt;

进行扩展,如果我们想多查一个订单号orderNo,第一种写法可以这样写:

.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no, order_no ")
.lambda()

但是这样写的坏处就是,不够优雅,而且如果在java里改了属性名,会导致查询出问题,这也是我们想用LambdaQueryWrapper的原因。

但如果按照下面这种写法,也存在问题:

.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ")
.lambda()
.select(OrderModel::getOrderNo)

这样写会导致我们在QueryWrapper写的select被LambdaQueryWrapper覆盖调。所以第二种做法行不通,但不想用第一种写法,想用lambda,那么就得解决第二种写法出现的问题。

通过查看LambdaQueryWrapper的select方法,发现它是使用SFunction接收参数,并把参数使用stream流转成字符串。

LambdaQueryWrapper 调用mysql函数 lamdaquerywarpper groupby_java


LambdaQueryWrapper 调用mysql函数 lamdaquerywarpper groupby_聚合函数_02


那么,具体思路就有了,我们把SFunction根据流的方式,转成字符串,代码如下:

/**
     * 处理sql查询字段名
     * @param columns
     * @return
     */
    private String getParamSql(SFunction<OrderModel, ?>... columns) {
        return Arrays.stream(columns).map(c -> StrUtil.toUnderlineCase(LambdaUtils.getName(c))).collect(Collectors.joining(StringPool.COMMA, StringPool.SPACE, StringPool.SPACE));
    }

通过Arrays.stream()为可变数组创建流,然后使用LambdaUtils.getName()方法获取属性名,再用StrUtil.toUnderlineCase()把属性名从,小驼峰转成下划线,最后用.collect(Collectors.joining())拼成字符串,用逗号分隔,前后加空格。

然后我们就可以通过这个方法使用lambda啦,因为入参是用可变数组,所以所以传入多个,这里只传入一个orderNo。

.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ", getParamSql(OrderModel::getOrderNo))
.lambda()

完整代码如下:

Page<OrderModel> page = orderService.page(new Page<>(1, 20), new QueryWrapper<OrderModel>()
	.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ", getParamSql(OrderModel::getOrderNo))
	.lambda()
	.between(StrUtil.isNotBlank(commandReq.getStartDate()) && StrUtil.isNotBlank(commandReq.getEndDate()),
                        OrderModel::getTradeDate,
                		StrUtil.isNotBlank(startDateStr) ? LocalDate.parse(startDateStr) : null,
                		StrUtil.isNotBlank(endDateStr) ? LocalDate.parse(cendDateStr) : null)  
    .groupBy(OrderModel::getMerNo));

虽然看起来还是不够优雅,但是我觉得已经是最优的方案了,如果有更好的写法,可以在评论区留言。
写法绝对是本人自己思考后写出来的,因为在网上搜了一个多小时,也没看到什么更优雅的写法,如果本篇文章对你有帮助的话,就动动点击下方大拇指,给个免费的赞,不然我真的会谢。