mybatis-plus小课堂:多表查询【案例篇】(apply 拼接 in SQL,来查询从表某个范围内的数据)

1,973 阅读1分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

引言

mybatis-plus小技能:多表查询【预备知识篇】blog.csdn.net/z929118967/…

内外连接:blog.csdn.net/z929118967/…

mybatis-plus小技能:多表查询【案例篇】blog.csdn.net/z929118967/…

I 多表查询

1.1 多表查询:在mapper.xml 写语句和拼接查询条件

在mapper.xml 写语句,对应方法写到mapper里,service可以注入对应的mapper进行调用。

.xml

    <select id="selectProfitTradeActivityList"
            resultType="com.dto.TradeActivityDto"
            parameterType="com.dto.GenerateTradeQuery">
        select a.id,a.trade_no,a.activity_type,a.activity_code
        from trans_flow t
        inner join trans_flow_activity a on t.trade_no = a.trade_no
        <where>
            t.trade_state='S' and a.pay_channel_id='XYD'
            <if test="ps.startTradeTime != null">
                and t.trade_time &gt;= #{ps.startTradeTime}
            </if>

        </where>
--         order by t.update_time desc
    </select>
@Mapper
public interface TransFlowActivityMapper extends BaseMapper<TransFlowActivity> {

    List<GenerateTradeActivityDto> selectProfitTradeActivityList(@Param("ps") GenerateTradeQuery input);

}

1.2 多表关联:Java代码中书写语句和拼接查询条件

实现思路:

  • 使用 Select注解书写sql语句
  • 采用apply方法自定义sql拼接条件, 使用条件构造器作为参数。
  1. 驱动表表和辅表的参数拼接

${ew.customSqlSegment} 条件构造器作为参数都需要添加前缀,否则如果有字段重名就无法明确使用哪一个。

        lambda.apply("m.state = {0}", EMerchantState.NORMAL);
  1. 书写SQL

1.3 案例:左外连接

实现思路:

  • 使用 Select注解书写sql语句/xml书写语句。
  • 采用apply方法自定义sql拼接条件, 使用wrapper条件构造器作为参数。

实现步骤:

  1. 定义查询接口: mapper.java/Service.java
  • Service层
@Override
    public List<RiskEquipmentPositionDto> getlist(LambdaQueryWrapper<RiskEquipmentPosition> input) {
        return baseMapper.getList(input);
    }
  1. Mapper层:采用 ${ew.customSqlSegment}@Param(Constants.WRAPPER)实现,将条件构造器作为参数。

  2. 书写SQL 方式一:使用Select注解书写sql语句

@Select("select r.* ,m.merchant_name,m.facilitator_id,m.facilitator_name,m.facilitator_top_id,m.facilitator_top_name from risk_equipment_position r left join mer_merchant m on r.merchant_id = m.merchant_id ${ew.customSqlSegment} ")
    List<RiskEquipmentPositionDto> getList(@Param(Constants.WRAPPER) LambdaQueryWrapper<RiskEquipmentPosition> input);

where后面的内容就是条件构造器生成的部分

方式2: 使用xml书写语句

  1. 拼接查询条件
LambdaQueryWrapper<RiskEquipmentPosition> lambda = new LambdaQueryWrapper<>();
        lambda.orderByDesc(TRiskEquipmentPosition::getCreateTime);
        if (input.getStartTime() != null) {
            lambda.ge(RiskEquipmentPosition::getCreateTime, input.getStartTime());
        }
        if (input.getEndTime() != null) {
            lambda.lt(RiskEquipmentPosition::getCreateTime, input.getEndTime());
        }
        if (input.getState() != null) {
            lambda.eq(RiskEquipmentPosition::getState, input.getState());
        }
        // 终端SN、商户号本表查询,其他关键词需要关联商户表进行查询。
        if (null != input.getKeywordType() && StringUtils.isNotBlank(input.getKeyword())) {

            var keyWordTypes = new ArrayList<String>();
            keyWordTypes.add(ERiskEquipmentPositionKeyWord.MER_ID.getCode());
            keyWordTypes.add(ERiskEquipmentPositionKeyWord.FAC_ID.getCode());
            keyWordTypes.add(ERiskEquipmentPositionKeyWord.TOP_ID.getCode());
            Long longKeyWord = 0L;
            if (keyWordTypes.contains(input.getKeywordType())) {
                try {
                    longKeyWord = Long.parseLong(input.getKeyword());
                } catch (Exception ex) {
                    throw CommonException.create(ServerResponse.createByError("无效的编号"));
                }
            }
            switch (BaseEnum.getEnum(ERiskEquipmentPositionKeyWord.class, input.getKeywordType())) {
                case SN:
                    lambda.eq(RiskEquipmentPosition::getEquipmentSn, input.getKeyword());
                    break;
                case MER_ID:
                    lambda.apply("r.merchant_id = {0}",input.getKeyword());
                    break;
                case MER_NAME:
                    lambda.apply("m.merchant_name = {0}",input.getKeyword());
                    break;
                case FAC_ID:
                    //apply方法用于拼接自定义的条件判断,如果自定义的条件判断是需要独立的结果,就必须记得加括号。
                    lambda.apply("m.facilitator_id = {0}",input.getKeyword());
                    break;
                case FAC_NAME:
                    lambda.apply("m.facilitator_name = {0}",input.getKeyword());
                    break;
                case TOP_ID:
                    lambda.apply("m.faclitator_top_id= {0}",input.getKeyword());
                    break;
                case TOP_NAME:
                    lambda.apply("m.facilitator_top_name= {0}",input.getKeyword());
                    break;
            }

        }
        // 分页查询
        PageHelper.startPage(input.getPageNum(), input.getPageSize());
        List<RiskEquipmentPositionDto> positionList = tRiskEquipmentPositionService.getlist(lambda);
        PageInfo pageInfo = new PageInfo(positionList);
        PageHelper.clearPage();
        return pageInfo;
  1. 调用查询接口
        List<RiskEquipmentPositionDto> positionList = RiskEquipmentPositionService.getlist(lambda);

II mybatis-Plus 之 apply 拼接 in SQL

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)

2.1 apply源码实现

    protected final String formatSqlMaybeWithParam(String sqlStr, String mapping, Object... params) {
        if (StringUtils.isBlank(sqlStr)) {
            return null;
        } else {
            if (ArrayUtils.isNotEmpty(params)) {
                for(int i = 0; i < params.length; ++i) {
                    String target = "{" + i + "}";
                    sqlStr = sqlStr.replace(target, this.formatParam(mapping, params[i]));
                }
            }

            return sqlStr;
        }
    }

2.2 apply 拼接 in SQL

从源码可以看出第二参数params 无法使用字符串"1,2"形式。

                lambda.apply("m.nature in ({0})","1,2");

如果params使用数组只会获取第一个元素。

正确的实现方式如下:直接在applySql拼接完整

                String sql = "m.nature in ("+activity.getMerchantNatures()+")";                lambda.apply(sql);//activity.getMerchantNatures()

如果是主表条件可以使用

                lambda.in(TMerMerchant::getNature, natures);//(nature IN (?,?)

III 常见问题

3.1 Cause: comColumn 'xxx' in where clause is ambiguous

需求: wrapper自定义sql: 使用条件构造器作为参数 1. mapper.java/Service.java定义接口方法 2. 只需添加 ${ew.customSqlSegment}@Param(Constants.WRAPPER)即可

    @Select("select m.* ,p.merchant_code,p.first_in_net_time from t_mer_merchant m  join t_mer_pay_net_register p on m.merchant_id = p.merchant_id    ${ew.customSqlSegment} ")
    List<MktAllowMerchaterDto> getList(@Param(Constants.WRAPPER)  LambdaQueryWrapper<TMerchant> lambda);

${ew.customSqlSegment} 条件构造器作为参数都需要添加前缀,否则如果有字段重名就无法明确使用哪一个。

修复方式:

        lambda.apply("m.state = {0}", EMerchantState.NORMAL);