Mysql动态查询字段及${}和#{}

130 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

业务场景,由于每个用户关注点不一样,比如工程,更加注重设备工程效率,工程时长;设备更加关注设备本身属性:质量,温度,转速等;而实际的生产经理可能更关注设备的投入产出和经营效率;那么需要定制化设备信息字段,根据用户偏好配置不同的字段,展示对应的信息。因此,同一个业务场景就需要差异化和具体化,人性化;我们可以直接在sql中搞定。

第一步:传入参数需要显示的字段和查询条件。

1、list:封装的查询字段,可以是string类型list或者是对象类型的list。

2、requestAssembly:封装的请求参数

*Mapper.java

List<KeyValueVo> selecCount(@Param("list")List<KeyValueDto> list, @Param("requestAssembly")RequestAssembly requestAssembly);

第二步:创建动态sql

*Mapper.xml

<select id="selecCount" resultType="com.xxx.base.bean.KeyValueVo">
    select name,code,countTotal from (
<foreach collection="list" item="item"  open="(" close=")" separator="union">
   (
    select
    '${item.text}' as `name`,
    '${item.value}' as `code`,
    '${item.sortIndex}' as `sortIndex`,
    (case when '${item.id}' = 'a' then ifnull(sum(a.a_normal+a.a_exception+a.a_offline),0)
         when '${item.id}' = 'b' then ifnull(sum(a.b_exception+a.b_normal++a.b_offline),0)
         when '${item.id}' = 'c' then ifnull(sum(a.c_normal+a.c_exception+a.c_offline),0)
         when '${item.id}' = 'd' then ifnull(sum(a.d_normal+a.d_exception+a.d_offline),0)
         when '${item.id}' = 'e' then ifnull(sum(a.e_normal + a.e_exception + a.e_offline),0)
         when '${item.id}' = 'f' then ifnull(sum(a.f_normal + a.f_exception + a.f_offline),0)
         when '${item.id}' = 'g' then ifnull(sum(a.g_normal + a.g_exception + a.g_offline),0)
         else ifnull(sum(a.others_normal+a.others_exception+a.others_offline),0)
         end ) as countTotal
    from cloud_xxxx_equip_info a
    where a.business_type = '2'
    <if test="requestAssembly.projectCode != null  and requestAssembly.projectCode != '' " >
     and project_code = #{requestAssembly.projectCode,jdbcType=VARCHAR}
    </if>
    <if test="requestAssembly.requestId != null and requestAssembly.requestId != '' " >
     and person_id = #{requestAssembly.requestId,jdbcType=VARCHAR}
    </if>
    <if test="requestAssembly.taskIds != null and requestAssembly.taskIds != '' " >
     and  FIND_IN_SET(renwu_id,#{requestAssembly.taskIds,jdbcType=VARCHAR})
    </if>
    )
</foreach>
) aa where aa.countTotal>0
order by aa.sortIndex desc,${requestAssembly.orderField} ${requestAssembly.orderType}
</select>

三、在查询条件的请求实体中,增加两个字段orderField和orderType,⽤于传⼊字段名和排序的⽅式(升序ASC,降序DESC)

orderField:⽤于接收需要排序的字段

orderType:⽤于接收排序的⽅式,ASC,DESC,asc,desc

ORDER BY ${orderField} ${orderType}

四、【特别注意】:此处排序SQL的两个参数和动态字段,⼀定要使⽤ ${}接收,⽽不能使⽤ #{}。否则不会到达预期的效果。

1、${}:不会对传⼊的字符串进⾏处理。⽐如:传⼊的是 create_time 和 desc,${}处理后的效果是 ORDER BY create_time desc,可以实现按照 create_time字段倒序排序的效果。

2、#{}:会对传⼊的字符串进⾏处理。⽐如:传⼊的是 create_time 和 desc,#{}处理后的效果是 ORDER BY 'create_time' 'desc',会当成字符串常量,达不到按照 create_time字段倒序排序的效果。

当然,${}可能会引发SQL注⼊。⼀般情况下,都是使⽤#{}的。只有这种不需要对传⼊的值进⾏转换的场景,比如表名和字段,才会使⽤${}