一、SQL 多条件来查询
1、在 EmployeeMapper 接口中声明方法
//根据id, lastNname, age, sex多条件查询员工信息
public List<Emp> getEmpListByMoreCondition(Emp emp);
2、在 EmployeeMapper.xml 中配置 SQL 语句
<!--
public List<Emp> getEmpListByMoreCondition(Emp emp);
多条件查询:若页面中没有设置此条件,SQL语句中一定不能有该条件
-->
<select id="getEmpListByMoreCondition1" resultType="Emp">
select eid,ename,age,sex,did from emp
where
id = #{id}
and last_name = #{lastName}
and age = #{age}
and sex = #{sex}
</select>
在这里可以看到,使用的是 SQL 拼接的方式,来进行多条件查询的。
二、使用 if 标签实现多条件查询
1、在 EmployeeMapperDynamicSQL 接口中声明方法
public List<Employee> getEmpsByConditionIf(Employee employee);
2、在 EmployeeMapperDynamicSQL.xml 中进行配置
<!--
1、查询员工:要求携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
-->
<!--
test:判断表达式(OGNL)表达式
OGNL 表达式参照官方文档或PPT
c:if test
从参数中取值进行判断
遇见特殊符号应该去写转义字符:
" : "
& : &
OGNL 会进行字符串和与数字的转换判断
-->
<select id="getEmpsByConditionIf" resultType="Employee">
select * from tbl_employee
where
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null and lastName!=''">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email = #{email}
</if>
<if test="gender==0 or gender==1">
and gender = #{gender}
</if>
</select>
<if> 标签的作用:通过 test 表达式,用于拼接 SQL,如果 test 为 true,将其中的 SQL 进行拼接,否则不进行拼接。
3、细节问题1
当我们把 gender 字段改为"男、女"的字符格式时,然后重新修改 xml 中的配置:
<select id="getEmpsByConditionIf" resultType="Employee"> select * from tbl_employee <where> <if test="id!=null"> id=#{id} </if> <if test="lastName!=null and lastName!=''"> and last_name like #{lastName} </if> <if test="email!=null and email.trim()!="""> and email = #{email} </if> <if test="gender == '男' or gender == '女'"> and gender = #{gender} </if> </where> </select>
测试信息:
@Test
public void testIf() throws IOException {
//1、获取 sqlSessionFactory
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
//2、获取 sqlSession 实例,能直接执行已经映射的 SQL 语句
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
//select * from tbl_employee where id=? and last_name like ? and email = ?
Employee employee = new Employee(null, "%o%", "男","tom@126.com");
List<Employee> emps = mapper.getEmpsByConditionIf(employee);
emps.forEach(System.out::println);
} finally {
sqlSession.close();
}
运行结果:
我们发现,这时并不能正常执行。
重新修改配置文件:
<select id="getEmpsByConditionIf" resultType="Employee"> select * from tbl_employee <where> <if test="id!=null"> id=#{id} </if> <if test="lastName!=null and lastName!=''"> and last_name like #{lastName} </if> <if test="email!=null and email.trim()!="""> and email = #{email} </if> <if test='gender == "男" or gender == "女"'> and gender = #{gender} </if> </where> </select>
修改了映射文件,重新运行。
运行成功。
小结:
(1)if 标签中判断字符串变量是否是字符串的时候,发现并不管用;
(2)如果把变量的值用双引号引起来,外面使用 单引号,这时就成功了;
(3)只能解释为 MyBatis 会把 '男' 解析为字符,而需要的是字符串,java 是强类型语言,字符串和字符不能直接比较,所以需要使用双引号。
4、细节问题2
对于上面的拼接条件,如果使用了多条件拼接查询,当有多个匹配条件时,可以使用 and 来连接。
但是如果第一个条件如果不进行拼接,就会出现 where 后面多出一个 and 的情况。
例如上面的情况,如果 id 为 null,就不会进行拼接该 SQL 片段,而是直接拼接第二个条件,这时就会出现一个 and 字段
select * from tbl_employee where and last_name = ? and email = ? and gender = ?
这时 SQL 的执行就会出现问题。
5、解决方案一
在 where 后面添加一个恒成立的情况,如果第一个条件不匹配,也不会不执行。
<select id="getEmpsByConditionIf" resultType="Employee">
select * from tbl_employee
where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="lastName!=null and lastName!=''">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email = #{email}
</if>
<if test="gender==0 or gender==1">
and gender = #{gender}
</if>
</select>
执行的 SQL 语句:
select * from tbl_employee where 1=1 and last_name = ? and email = ? and gender = ?
常用的恒等式有:
2>1
1=1
true
6、解决方案二
使用下面的 where 标签
三、使用 where 条件
<select id="getEmpsByConditionIf" resultType="Employee">
select * from tbl_employee
<where>
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null and lastName!=''">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email = #{email}
</if>
<if test="gender==0 or gender==1">
and gender = #{gender}
</if>
</where>
</select>
select * from tbl_employee WHERE last_name like ? and email = ?
注意:
(1)if 标签和 where 标签不一定必须同时使用,按实际需要进行使用;
(2)if 标签用于完成简单的判断;
(3)where 用于解决 SQL 语句中 where 关键字以及条件中第一个 and 或者 or 的问题;
(4)mybatis就会将where标签中拼装的sql,多出来的and或者or去掉,where只会去掉第一个多出来的and或者or。
四、总结
查询的时候如果某些字段没带可能 SQL 拼装会有问题。
(1)给 where 后面加上1=1,以后的条件都是 and xxx;
(2)mybatis 使用where标签来将所有的查询条件包括在内,mybatis 就会将where标签中拼装的SQL,多出来的and或者or去掉;
(3)where 只会去掉第一个多出来的and或者or;