先举个例子,我们去买饼干,我想要的饼干是绿色威化饼干,这时候Left Join On()里就是“绿色”和“威化饼干”两个条件。必须先同时符合这两个条件,买回来绿色威化饼干,我们才能谈后续对于它的条件筛选:比如说找到方形的、圆形的、三角形的。
但如果我们先只给On()传输一个“绿色”,我们买回来的是可能是绿色曲奇饼干、绿色苏打饼干、绿色夹心饼干等。这时再追加一个“威化饼干”的and条件,虽说也会找到一些“绿色威化饼干”,但是会出现许多多余的、错误的饼干,这都是我们不需要的,我们却费劲买回来了。更不要提后续对于饼干大小、形状等其他条件的筛选啦。
理解了这个例子以后,再来看On、Where、And条件也不迟。
在 mapper.xml中填写SQL语句,在<if>标签中加入and条件来拼接,但在拼接and之前要先有个where条件。可以写成where 1 = 1,再给后面拼接其他条件。如果不加where直接拼接and,编译器会认为and后的条件为联合查询时的条件,不能起到过滤作用。
select sl.create_time,
sl.username,
sl.operate_type,
sl.log_content,
sdi.item_text
from sys_log sl
left join sys_dict_item sdi
on (sl.operate_type = sdi.item_value and sdi.dict_id = "880a895c98afeca9d9ac39f29e67c13e"
)
where 1 = 1
<if test="SysLogTest.username != null">
and username like concat ('%', #{SysLogTest.username}, '%')
</if>
<if test="SysLogTest.selectCreateTime != null">
and datediff(create_time, #{SysLogTest.selectCreateTime})= 0
</if>
<if test="SysLogTest.logContent != null">
and log_content = #{SysLogTest.logContent}
</if>
这里我们着重要注意的点是Left Join On()里的联查条件。在此处我们有两种写法,第一种是常规写法,我们先将两张表联合成一张临时表,然后再在其中根据and条件筛选数据:
left join sys_dict_item sdi
on (sl.operate_type = sdi.item_value)
where 1 = 1
and sdi.dict_id = "880a895c98afeca9d9ac39f29e67c13e"
and ......
或者是在on中加入几个先决and条件,先根据on中的条件联合两张表生成一张临时表,然后再在这张临时表中根据and条件筛选:
left join sys_dict_item sdi
on (sl.operate_type = sdi.item_value and sdi.dict_id = "880a895c98afeca9d9ac39f29e67c13e")
where 1 = 1
and ......
这样写实际上是有区别的,在联查操作中,会先根据Left Join On()中的条件合成一张临时表,再进行后续的查询。第一种写法只会根据 sl.operate_type = sdi.item_value 这个条件,合成临时表,再查询;第二种写法则需要同时符合两个条件,再合成临时表。看起来似乎两者并没有什么区别,但实际上会产生很大的偏差。
这是按照第二种写法生成的正确数据,因为我们给item_text对应了我所需要的dict_id,先根据on()中的两个条件生成了数据表,再生成数据。再做后续的筛选操作,没有任何问题。
但如果我们先生成临时表,表中item_text可能已经不是我所需要的item_text,它指向了错误的dict_id。生成数据时,也就完全不是我想要的,后续的任何操作也都会产生错误。
一定要注意On、Where、And的使用顺序带来的差异。