近日在写后台接口的过程中处理到了一个关于Mysql联表根据条件选择副表的需求,某系统管理模块,借此记录一下,与大家一起分享探讨。
应用场景简述:在管理员管理用户信息时,用户类型分为两种,一种简称为A用户类型吧,一种简称为B用户类型。User表中管理的是账号的数据,具体用户信息关联在详细的A表与B表当中。在获取用户列表时,需要判定user表中用户的类型为A还是B,再决定去A表还是B表获取用户的详细信息保存到相应的bean中通过接口返回JSON数据供前端展示。
实现目标:
在接口中正确的返回用户信息给前端,并且无常规报错(空指针,sql错误等),并且能根据前端传输过来的查询条件正确的返回相应的过滤数据。
解决思路:
1.以user表作为主表。
2.分别joinA表和B表。
3.通过User表中的type来判定最终需要获取哪张表的数据。
4.通过A/B表中user_id来确定是表中的哪条数据,并返回数据。
select t.id,t.name,t.type,a.status as a_status,a.service_status as a_service_status,b.service_stastus as b_service_stastus,b.status as b_status a.name as a_name,b.name as b_name from t_user t left join t_A a on (t.type = A and t.id = a.user_id) left join t_B b on (t.type = B and t.id = b.user_id) where (t.type = A or t.type = B)
这里其实是能查出数据的,因为A表与B表中有相同命名的字段,而返回到前端的时候让前端自行判断是哪个类型的数据取相应的字段名显然是有些不合理的,所以我们还需要优化,因为一行User表中数据关联的只能A或B表中的某一条数据,所以查询出来不是A表的这些字段为null就是B表的这些字段为null,只能有一条对应的详细数据。所以在此时我们需要优化,在Bean中也不用定义那么多字段,只要把sql写好,便可减少一些代码量,也不用要求前端做校验,拿到数据直接展示就好。
优化之后:
select t.id,t.name,t.type,if(a.status is null,b.status,a.status) as status ,if(a.service_status is null,b.service_stastus,a.service_status) as serviceStatus, if(a.name is null,b.name,a.name) as name from t_user t left join t_A a on (t.type = A and t.id = a.user_id) left join t_B b on (t.type = B and t.id = b.user_id) where (t.type = A or t.type = B)
这时候我们用上了mysql的if函数,关于if函数的概念是这样的
IF函数根据判断条件是否成立进行选择执行,成立时执行一条语句,不成立时执行另一条语句
IF(condition, value_if_true, value_if_false)
condition: 判断条件
value_if_true: 如果condition的结果为TRUE,返回该值
value_if_false: 如果condition的结果为FALSE,返回该值
用上了if函数之后如果a表的一些数据查出来为null数据时就会自动将b表中的内容填充上去,而a表若有数据则不使用b表的数据,接下来愉快的在mapper文件中写上我们的sql。
<sql id="formList">
from t_user t left join t_A a on (t.type = A and a.user_id = t.id)
left join t_B b on (t.type = B and t.id = b.user_id)
<where>
<if test="name != null and name != ''">(a.name like CONCAT('%',#{name},'%') or b.name like CONCAT('%',#{name},'$')) and </if>
<if test="type != null">t.type =#{type} and </if>
<if test="serviceStatus != null">(a.service_status =#{serviceStatus} or b.service_status =#{serviceStatus}) and </if>
<if test="status != null">(a.status =#{status} or b.status =#{status}) and </if>
t.type != 0
</where>
</sql>
<select id="getUserList" parameterType="map" resultType="UserListVO">
select t.id,t.name,t.type,if(a.`status` is null,b.`status`,a.`status`) as status ,if(a.service_status is null,b.service_status,a.service_status) as serviceStatus,
if(a.name is null,b.name,a.name) as name
<include refid="formList" />
order by t.id desc
</select>
<select id="getUserList" parameterType="map" resultType="integer">
select count(1)
<include refid="formList" />
</select>
这是mybatis的写法,顺便提醒下,如果有使用or的情况下,记得把括号括好,不然容易出些bug,至此,需求完成,git提交,下班下班。
关于if函数概念的原文链接:blog.csdn.net/Hudas/artic…
感谢各位能够观看至此~