menu是一个菜单表,user_menu是一个用户分配到的菜单。
menu表里记录了每个菜单和他的父级菜单。
现在我想用一个SQL语句,在USER_MENU表中找出,哪个用户分配了一个没有子级菜单的菜单。并把这条记录删除。
create table menu(
menu_id varchar2(4000),
parent_menu_id varchar2(4000),
menu_name varchar2(4000)
); create table user_menu(
user_id varchar2(4000),
menu_id varchar2(4000)
);MENU_ID         PARENT_MENU_ID  MENU_NAME
M1001001 M1001         财务表数据查询
M1001002 M1001          员工表数据查询
M1001                 查询菜单
M1001001001 M1001001 员工日用品领用查询USER_ID MENU_ID
USER_1 M1001001
USER_1 M1001001001
USER_2 M1001001
如上图:
我需要找到哪个用户分配的菜单,没有下级菜单的。
这里,只有USER_2分配了这样的菜单。所以要找到的结果应该是(USER_ID,MENU_ID)=(USER_2,M1001001)
----------------------------------
我自己用了一个比较傻的办法,但觉得效率比较低。请SQL高手帮我看看,有没有比较好的SQL语句,可以达到这个目的。谢谢。我认为,有父亲节点的或有儿子节点的,肯定是不需要删除的。除此以外的应该就是要删除的菜单。
select * from user_menu m where (m.user_id,m.menu_id) not in 
(
-- 有孩子节点的父亲节点
select tt.user_id,tt.menu_id
from  user_menu tt inner join 
user_menu rt1 on rt1.user_id = tt.user_id
inner join menu rt2 on rt1.menu_id=rt2.menu_id
where tt.menu_id=rt2.parent_menu_id 
)
and (m.user_id,m.menu_id) not in (
-- 有父节点的孩子节点
select tt.user_id,tt.menu_id
from  user_menu tt  inner join menu rt1 on tt.menu_id=rt1.menu_id
inner join user_menu rt2 on rt1.parent_menu_id = rt2.menu_id
)
 
SQL

解决方案 »

  1.   

    CONNECT BY 结合CONNECT_BY_ISLEAF 或许可以实现你的要求
      

  2.   

    记录数太少,需求有漏洞,
    我需要找到哪个用户分配的菜单,没有下级菜单的。
    USER_1 M1001001001 这条记录也没有下级菜单,算不算呢
      

  3.   

    不算。 这里要删除的是,分配了一个没有父菜单和子菜单的菜单。假如:菜单的层级是MENU_A1>MENU_A2>MENU_A3(这里用大于号表示父子关系,大于号的左边是父亲)。
    那么,下述记录中,USER_1分配的菜单M1001001>M1001001001他们是有父子关系的父子菜单。所以虽然M1001001001没有下级菜单,也不能删除。
    USER_1 M1001001
    USER_1 M1001001001
      

  4.   

    有子菜单的所有菜单:select * from menu where menu_id in (select parent_menu_id from menu);不存在一条记录,满足同一个用户 分配 有子菜单的菜单:select * from user_menu m where not exists
    (select 1 from user_menu t where t.user_id=m.user_id and t.menu_id in (select parent_menu_id from menu));