当我们在平时中需要通过以逗号隔开的,查询其中含有的数据时,我们会需要用到一个mysql函数,FIND_IN_SET
是MySQL中的一个函数,它返回一个字符串在由逗号分隔的字符串列表中的位置。这个函数通常用于在SQL查询中处理以逗号分隔的列表。
当我们需要查询的时候,就需要下面这样的sql才能进行多个以逗号隔开的查询条件进行拼接,但是呢,在mybatis-puls中怎么写这样的sql呢。
SELECT DISTINCT c.id,c.semesterid,c.professionid,c.classid,c.teacherid,c.courseid,c.classroomid,c.`week`,c.weekbyday,c.section,c.studentnumber,c.`status`,c.remark FROM c_coursearrange c JOIN sys_user_role sur ON c.teacherid = sur.user_id JOIN sys_role r ON sur.role_id = r.id AND FIND_IN_SET('1', week) > 0 AND FIND_IN_SET('2', week) > 0 AND FIND_IN_SET('1', section) > 0 AND FIND_IN_SET('2', section) > 0 AND FIND_IN_SET('1', weekbyday) > 0 AND FIND_IN_SET('4', weekbyday) > 0
Controller层接口是这么写的,控制层是通过QueryWrapper<CCoursearrange> queryWrapper = new QueryWrapper<>(); 方法进行查询的,queryWrapper.last(build)表示在sql最后面添加where条件的sql。
@GetMapping(value = "/list")
public Result<IPage<CCoursearrange>> queryPageList(CCoursearrange cCoursearrange,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<CCoursearrange> queryWrapper = new QueryWrapper<>();
Page<CCoursearrange> page = new Page<CCoursearrange>(pageNo, pageSize);
// 判断传过来的查询参数是否为null,为null则不进行此操作,反之进行
String build = CCoursearrangeController.buildSqlConditions(cCoursearrange);
//在sql最后面添加sql
queryWrapper.last(build);
IPage<CCoursearrange> pageList = cCoursearrangeService.findTeacherByCoursearrangePage(page, queryWrapper);
return Result.OK(pageList);
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!写了方法在下面
/**
* 判断传过来的查询参数是否为null,为null则不进行此操作,反之进行
* @param cCoursearrange
* @return
*/
public static String buildSqlConditions(CCoursearrange cCoursearrange) {
// 判断是否为null,为null则不进行此操作,反之进行
String[] weeksToCheck = null;
if (cCoursearrange.getWeek() != null) {
weeksToCheck = cCoursearrange.getWeek().split(",");
}
String[] sectionsToCheck = null;
if (cCoursearrange.getSection() != null) {
sectionsToCheck = cCoursearrange.getSection().split(",");
}
String[] weekByDaysToCheck = null;
if (cCoursearrange.getWeekbyday() != null) {
weekByDaysToCheck = cCoursearrange.getWeekbyday().split(",");
}
// 构建 FIND_IN_SET 的sql条件,判断是否有查询值,有则添加后面的sql
String findInSetConditions = CustomQueryUtils.buildFindInSetConditions(weeksToCheck, sectionsToCheck, weekByDaysToCheck);
return findInSetConditions;
}
mapper层,mybatisplus是在最后面添加${ew.customSqlSegment}进行条件查询,这样就不需要通过xml进行if判断了。
// 教师所教课程排班
@Select("SELECT DISTINCT c.id,c.semesterid,c.professionid,c.classid,c.teacherid,c.courseid,c.classroomid,c.`week`,c.weekbyday,c.section,c.studentnumber,c.`status`,c.remark FROM c_coursearrange c JOIN sys_user_role sur ON c.teacherid = sur.user_id JOIN sys_role r ON sur.role_id = r.id ${ew.customSqlSegment} ")
IPage<CCoursearrange> findTeacherByCoursearrangePage(Page<CCoursearrange> page, @Param("ew") Wrapper<CCoursearrange> queryWrapper);
service层
@Override
public IPage<CCoursearrange> findTeacherByCoursearrangePage(Page<CCoursearrange> page, QueryWrapper<CCoursearrange> queryWrapper) {
return baseMapper.findTeacherByCoursearrangePage(page,queryWrapper);
}
写了一个util方法。这里面的三个if我并没有进行调优,就是写死了。你们可以根据需要多少查询条件进行编辑几个if判断。
简单说明一下:
- 处理weeks数组:
- 首先检查
weeks
数组是否非空且长度大于0。 - 使用
Arrays.toString(weeks).equals("[]")
来检查数组是否为空数组。 - 如果
weeks
数组非空,则不进行weeks的sql添加,然后继续判断下面的数组是否为空,不为空则进行添加FIND_IN_SET进行判断提交的数据中含有的字符。 - 使用
AND
来连接多个条件,并添加括号来确保逻辑的正确性。 - 通过循环遍历
weeks
数组,并使用FIND_IN_SET
函数来为每个元素构建条件。 firstCondition
变量用于跟踪是否已添加第一个条件,从而避免在第一个条件前添加多余的AND
。
- 首先检查
当您调用buildSqlConditions(cCoursearrange)
方法时,它会:
- 检查
cCoursearrange
对象的week
、section
和weekbyday
属性。 - 如果这些属性不为null,则将它们拆分为数组。
- 调用
buildFindInSetConditions
方法为这些数组构建SQL条件。 - 返回由
buildFindInSetConditions
生成的SQL条件字符串。
package org.jeecg.modules.classs.util;
import java.util.Arrays;
import java.util.Collection;
public class CustomQueryUtils {
/**
* 构建 FIND_IN_SET 条件的 SQL 片段
*
* @param weeks 包含周编号的集合
* @param sections 包含节次编号的集合
* @param weekByDays 包含星期几编号的集合
* 循环集合Collection<String>里面的数据进行动态添加sql
* @return SQL 片段字符串
*/
public static String buildFindInSetConditions(String[] weeks, String[] sections, String[] weekByDays) {
StringBuilder sb = new StringBuilder("");
if (weeks!=null && weeks.length>0) {
if (!Arrays.toString(weeks).equals("[]")){
sb.append(" AND (");
boolean firstCondition = true; // 用来跟踪是否已添加第一个条件
if (weeks.length>0){
for (String week : weeks) {
if (!firstCondition) { // 跳过第一个的 AND (
sb.append(" AND ");
}
sb.append("FIND_IN_SET('").append(week).append("', week) > 0");
firstCondition = false; // 标记第一个条件已添加
}
}
sb.append(")");
}
}
if (sections!=null && sections.length>0) {
if (!Arrays.toString(sections).equals("[]")){
sb.append(" AND (");
boolean firstCondition = true; // 用来跟踪是否已添加第一个条件
for (String section : sections) {
if (!firstCondition) { // 跳过第一个的 AND (
sb.append(" AND ");
}
sb.append("FIND_IN_SET('").append(section).append("', section) > 0");
firstCondition = false; // 标记第一个条件已添加
}
sb.append(")");
}
}
if (weekByDays!=null && weekByDays.length>0) {
if (!Arrays.toString(weekByDays).equals("[]")){
sb.append(" AND (");
boolean firstCondition = true; // 用来跟踪是否已添加第一个条件
for (String weekbyday : weekByDays) {
if (!firstCondition) { // 跳过第一个的 AND (
sb.append(" AND ");
}
sb.append("FIND_IN_SET('").append(weekbyday).append("', weekbyday) > 0");
firstCondition = false; // 标记第一个条件已添加
}
sb.append(")");
}
}
return sb.toString();
}
}
当我们点击查询的时候,就会产生以下的sql:
随后我们的sql在后面添加了我们需要的sql片段,查询到每个字段(以逗号隔开的数据)包含其中的。
SELECT DISTINCT c.id,c.semesterid,c.professionid,c.classid,c.teacherid,c.courseid,c.classroomid,c.`week`,c.weekbyday,c.section,c.studentnumber,c.`status`,c.remark FROM c_coursearrange c JOIN sys_user_role sur ON c.teacherid = sur.user_id JOIN sys_role r ON sur.role_id = r.id AND (FIND_IN_SET('1', week) > 0 AND FIND_IN_SET('2', week) > 0 AND FIND_IN_SET('3', week) > 0) AND (FIND_IN_SET('1', section) > 0 AND FIND_IN_SET('2', section) > 0 AND FIND_IN_SET('3', section) > 0 AND FIND_IN_SET('4', section) > 0) AND (FIND_IN_SET('1', weekbyday) > 0 AND FIND_IN_SET('2', weekbyday) > 0 AND FIND_IN_SET('3', weekbyday) > 0)