充分利用inner join 进行多表联查的优化

题目:找到所有拥有这个权标识(pemission)的用户

sys_menu 里面有权限标识 permission ,通过permission找到对应的menu_id
再通过menu_id在对应的sys_menus_rolse表里面找到对应的role_id
通过role_id 在sys_users_roles中找到对应的user_id
最后,用role_id在user表格中找到对应的user

表结构:

连接:招聘系统DEV
    数据库:ntby_zp
    	表:sys_user
               sys_menu
               sys_menus_roles
               sys_users_roles
  1. 原代码:(通过角色id查询用户信息)
SELECT sys_user.* FROM sys_user inner join (SELECT user_id FROM sys_users_roles where role_id =:roleId) as u on sys_user.user_id = u.user_id
  1. 辅助分析代码
    这里可以在sys_menu, sys_roles_menu两个表中查到permission对应的roleId
SELECT sys_roles_menus.role_id 
FROM `sys_roles_menus` 
inner join

(SELECT menu_id 
FROM `sys_menu` 
where permission = "customerManagerLogo") as r 
on sys_roles_menus.menu_id = r.menu_id 
  1. navicat中运行成功的代码
SELECT sys_user.* 
FROM sys_user 
inner join 

(SELECT user_id 
FROM sys_users_roles 
where role_id 

in 
(SELECT sys_roles_menus.role_id 
FROM `sys_roles_menus` 
inner join 

(SELECT menu_id 
FROM `sys_menu` 
where permission = "customerManagerLogo") as r 
on sys_roles_menus.menu_id = r.menu_id)) as u 

on sys_user.user_id = u.user_id

分析: 这种方法是先把条件查出来,然后再通过条件一层一层的往外扩大范围,去查询,表结构不清晰,比较不好梳理。

-- 复制到代码中
SELECT sys_user.* FROM sys_user inner join (SELECT user_id FROM sys_users_roles where role_id in (SELECT sys_roles_menus.role_id FROM `sys_roles_menus` inner join (SELECT menu_id FROM `sys_menu` where permission = :permission) as r on sys_roles_menus.menu_id = r.menu_id)) as u on sys_user.user_id = u.user_id
  1. 充分的利用inner join进行多表联查
select *,group_concat(distinct a.nick_name) 
from sys_user a
inner join sys_users_roles b
on a.user_id = b.user_id
inner join sys_roles_menus c
on b.role_id = c.role_id
inner join sys_menu d
on c.menu_id = d.menu_id
where permission = 'customerManager'
group by a.nick_name;

最后一列会多一列,但是并不影响数据的使用

这种方式是充分的利用了inner join 的特性,利用inner join 会对多个表进行连接,产生笛卡尔积的特性,
按照范围从大到小的方式,不断的缩小范围,从一个大的范围里面不断的加条件,从而找到自己想要的数据。

注意:

  1. 有几个表是取决于你查询的信息,以及连接条件中,是否有用到了这个表,用到则加,没用到则不要加。
  2. 在连接的时候,每连接一个表给一个表起一个别名,这样方便后面加条件。
  3. a b c d 4张表连接好以后,想取哪个表的字段就加上哪个表的字段
    ,想用哪个表筛选 就用哪个表筛选。
  4. 由于使用inner join,是利用了产生笛卡尔积的原理,所以可能有重复的数据的情况。在本题目中nick_name字段就出现了重复的情况。
    方法一:
    利用了这种结构
select *,group_concat(distinct name) from table group by name;

其中:
group_concat(),手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果。比较抽象,难以理解。
通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函数参数(就是字段名)决定。分组必须有个标准,就是根据group by指定的列进行分组。

所以要对该字段进行去重,同时还要把user里面的其他所有的字段还是出来,由于distinct只能对单个的字段进行去重,且只有写在开头才有作用。就有了这样的写法:

select distinct a.nick_name,a.* 
from sys_user a
inner join sys_users_roles b
on a.user_id = b.user_id
inner join sys_roles_menus c
on b.role_id = c.role_id
inner join sys_menu d
on c.menu_id = d.menu_id
where permission = 'customerManager'

结果:这种方式,多出来的一列在第一列

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值