SELECT am2.*,am.mid as submid,am.menuname as submenuname,am.url as suburl,am.glyphicon as subglyphicon
from admin_menu am
inner join admin_menu am2 on am.pid = am2.mid
用父表pid(父级字段)到子表mid进行匹配,用父表数据进行逐行匹配
1. 表结构
假设有三个表:
-
admin_menu
表:保存菜单的信息mid menuname pid url glyphicon 1 菜单管理 0 /menu icon1 2 子菜单1 1 /sub1 icon2 3 子菜单2 1 /sub2 icon3 4 用户管理 0 /user icon4 mid
:菜单的主键,唯一标识每个菜单。pid
:父菜单的mid
,表示该菜单的上级菜单,pid = 0
表示没有父菜单。
-
rel_admin_user_menu
表:用于存储用户与菜单的关联关系mid uid 1 1 2 1 3 2 mid
:菜单的mid
,表示该用户与哪些菜单有关联。
2. 查询解析
这条 SQL 查询实现了从 admin_menu
表中查询所有菜单数据,并通过两次自联接(INNER JOIN
)以及与 rel_admin_user_menu
表的关联来筛选出需要的数据。
-
admin_menu am
和admin_menu am2
的自联接:-
这是一个自联接(
INNER JOIN
),即同一个表admin_menu
被连接了两次,分别用别名am
和am2
。 -
连接条件是
am.pid = am2.mid
,意味着am
表中的每个菜单的父菜单(pid
)将与am2
表中的菜单的mid
字段进行匹配。换句话说,查询通过菜单的父子关系(pid
和mid
)将父菜单与子菜单关联起来。 -
am
表:表示的是父菜单(一级菜单)。 -
am2
表:表示的是子菜单(二级菜单)。
-
-
INNER JOIN rel_admin_user_menu ram
:- 这是与
rel_admin_user_menu
表的联接,用来筛选出与用户相关的菜单。 - 连接条件是
ram.mid = am.mid
,这意味着 该菜单必须在rel_admin_user_menu
表中与某个用户关联,即该菜单必须是某个用户可访问的菜单。
- 这是与
-
SELECT
子句:am2.*
:选择am2
表中的所有字段(即子菜单的所有字段)。am.mid AS submid
、am.menuname AS submenuname
、am.url AS suburl
、am.glyphicon AS subglyphicon
:从父菜单(am
表)中选择字段,并且给这些字段起别名(submid
,submenuname
,suburl
,subglyphicon
),以便清晰地指示这些字段对应的是父菜单的数据。
3. 查询的实现原理
-
自联接(
INNER JOIN
):-
SQL 中的自联接是通过给同一个表设置两个不同的别名来实现的。在这个查询中,
admin_menu am
代表父菜单,admin_menu am2
代表子菜单,am.pid = am2.mid
使得父菜单与子菜单根据父菜单的pid
字段和子菜单的mid
字段建立联系。 -
例如:
- 如果有一个菜单
mid = 1
(菜单管理),其pid = 0
,表示它是父菜单。 - 如果另一个菜单
mid = 2
(子菜单1),其pid = 1
,表示它是父菜单 1 的子菜单。
- 如果有一个菜单
-
-
联接条件:
am.pid = am2.mid
:父菜单am
的pid
必须与子菜单am2
的mid
匹配,确保正确地关联父子菜单。ram.mid = am.mid
:通过rel_admin_user_menu
表中的mid
字段与父菜单的mid
进行匹配,确保只有与用户关联的菜单才会被选择。
-
最终结果:
- 这个查询会返回所有符合条件的父子菜单关系,且查询结果将包含父菜单和子菜单的信息。每个子菜单会显示在结果集中,父菜单的字段(如
mid
,menuname
,url
,glyphicon
)会被赋予别名,例如submid
,submenuname
,suburl
,subglyphicon
,以避免字段名冲突。
- 这个查询会返回所有符合条件的父子菜单关系,且查询结果将包含父菜单和子菜单的信息。每个子菜单会显示在结果集中,父菜单的字段(如
4. 查询返回的结果
假设查询返回如下结果:
parent_mid | parent_menuname | sub_mid | sub_menuname | sub_url | sub_glyphicon |
---|---|---|---|---|---|
1 | 菜单管理 | 2 | 子菜单1 | /sub1 | icon2 |
1 | 菜单管理 | 3 | 子菜单2 | /sub2 | icon3 |
解释:
parent_mid
和parent_menuname
是从am
表(父菜单)中获取的字段。sub_mid
,sub_menuname
,sub_url
,sub_glyphicon
是从am2
表(子菜单)中获取的字段。am2
表的每一行代表一个子菜单(如sub_mid = 2
对应子菜单1
,sub_mid = 3
对应子菜单2
),并且它们的父菜单(parent_mid = 1
)通过am.pid = am2.mid
关联。
5. 为什么会有父子菜单的重复?
如果查询返回的结果中存在重复的父菜单数据,可能是由于 INNER JOIN
关联导致的。假设一个父菜单有多个子菜单,并且与多个用户关联,查询结果会根据这些关系返回多个记录,且每条记录中可能会出现相同的父菜单数据。MyBatis 或其他 ORM 框架通常会根据 mid
来去重,避免重复创建父对象。
总结
- 这条查询通过 自联接 和 与关联表的联接 来实现父子菜单的关系。
- 使用
INNER JOIN
来确保只查询有父菜单且与用户关联的菜单。 - 通过给父菜单和子菜单的字段起不同的别名,确保在结果中不会出现字段名冲突。
- 父菜单和子菜单之间的关系通过
pid
和mid
字段来建立,查询的结果返回父菜单与子菜单的联合数据。