【问题标题】:How do I handle permissions in my Oracle hierarchical menu query?如何处理 Oracle 分层菜单查询中的权限?
【发布时间】:2017-04-22 07:20:10
【问题描述】:

有一个菜单表:

create table MENU
(
   MENU_ID                        number(15,0) not null,
   PARENT_MENU_ID                 number(15,0),
   MENU_NAME                      varchar2(255 char) not null,
   PERMISSION_ID                  number(15,0)
)
/

还有数据:

INSERT INTO MENU VALUES (20,null,'Menu A',null);
INSERT INTO MENU VALUES (21,null,'Menu B',null);
INSERT INTO MENU VALUES (1001,null,'Menu C',null);
INSERT INTO MENU VALUES (1,1001,'Menu C-A',10);
INSERT INTO MENU VALUES (2,1001,'Menu C-B',34);
INSERT INTO MENU VALUES (3,1001,'Menu C-C',92);
INSERT INTO MENU VALUES (4,1001,'Menu C-D',57);
INSERT INTO MENU VALUES (16,1001,'Menu C-E',22);
INSERT INTO MENU VALUES (1002,1001,'Menu C-F',null);
INSERT INTO MENU VALUES (13,1002,'Menu C-F-A',28);
INSERT INTO MENU VALUES (14,1002,'Menu C-F-B',29);
INSERT INTO MENU VALUES (15,1002,'Menu C-F-C',43);
INSERT INTO MENU VALUES (1003,1001,'Menu C-G',null);
INSERT INTO MENU VALUES (5,1003,'Menu C-G-A',94);
INSERT INTO MENU VALUES (6,1003,'Menu C-G-B',11);
INSERT INTO MENU VALUES (7,1003,'Menu C-G-C',47);
INSERT INTO MENU VALUES (1004,1001,'Menu C-H',null);
INSERT INTO MENU VALUES (8,1004,'Menu C-H-A',120);
INSERT INTO MENU VALUES (9,1004,'Menu C-H-B',41);
INSERT INTO MENU VALUES (10,1004,'Menu C-H-C',52);
INSERT INTO MENU VALUES (11,1004,'Menu C-H-D',40);
INSERT INTO MENU VALUES (12,1004,'Menu C-H-E',39);
INSERT INTO MENU VALUES (2001,null,'Menu D',null);
INSERT INTO MENU VALUES (17,2001,'Menu D-A',14);
INSERT INTO MENU VALUES (18,2001,'Menu D-B',15);
INSERT INTO MENU VALUES (19,2001,'Menu D-C',106);
INSERT INTO MENU VALUES (3001,null,'Menu E',null);
INSERT INTO MENU VALUES (22,3001,'Menu E-A',16);
INSERT INTO MENU VALUES (4001,null,'Menu F',null);
COMMIT;

现在返回我所做的菜单结构:

select 
   level, 
   PARENT_MENU_ID,
   MENU_ID,
   SUBSTR(RPAD('-',(level-1),'-')||MENU_NAME,1,20) MENU,
   PERMISSION_ID
from
   MENU 
start with PARENT_MENU_ID is null
connect by prior MENU_ID = PARENT_MENU_ID
/

给予:

LEVEL      PARENT_MENU_ID MENU_ID    MENU                 PERMISSION_ID 
---------- -------------- ---------- -------------------- ------------- 
         1                        20 Menu A                            
         1                        21 Menu B                            
         1                      1001 Menu C                            
         2           1001          1 -Menu C-A                       10
         2           1001          2 -Menu C-B                       34
         2           1001          3 -Menu C-C                       92
         2           1001          4 -Menu C-D                       57
         2           1001         16 -Menu C-E                       22
         2           1001       1002 -Menu C-F                         
         3           1002         13 --Menu C-F-A                    28
         3           1002         14 --Menu C-F-B                    29
         3           1002         15 --Menu C-F-C                    43
         2           1001       1003 -Menu C-G                         
         3           1003          5 --Menu C-G-A                    94
         3           1003          6 --Menu C-G-B                    11
         3           1003          7 --Menu C-G-C                    47
         2           1001       1004 -Menu C-H                         
         3           1004          8 --Menu C-H-A                   120
         3           1004          9 --Menu C-H-B                    41
         3           1004         10 --Menu C-H-C                    52
         3           1004         11 --Menu C-H-D                    40
         3           1004         12 --Menu C-H-E                    39
         1                      2001 Menu D                            
         2           2001         17 -Menu D-A                       14
         2           2001         18 -Menu D-B                       15
         2           2001         19 -Menu D-C                      106
         1                      3001 Menu E                            
         2           3001         22 -Menu E-A                       16
         1                      4001 Menu F                            

这是最简单的部分。现在进入安全。假设我只想查看权限为 10、11、14 和 15 的所有菜单,那么我可以这样做:

select 
   level, 
   PARENT_MENU_ID,
   MENU_ID,
   SUBSTR(RPAD('-',(level-1),'-')||MENU_NAME,1,20) MENU,
   PERMISSION_ID
from
   MENU 
start with PARENT_MENU_ID is null
connect by prior MENU_ID = PARENT_MENU_ID
and PERMISSION_ID in (10,11,14,15)
/

给予:

LEVEL      PARENT_MENU_ID MENU_ID    MENU                 PERMISSION_ID 
---------- -------------- ---------- -------------------- ------------- 
         1                        20 Menu A                            
         1                        21 Menu B                            
         1                      1001 Menu C                            
         2           1001          1 -Menu C-A                       10
         1                      2001 Menu D                            
         2           2001         17 -Menu D-A                       14
         2           2001         18 -Menu D-B                       15
         1                      3001 Menu E                            
         1                      4001 Menu F                            

但这会忽略 PERMISSION_ID=11 的菜单,并包括没有子菜单的父菜单。理想情况下,我希望包含 11 个父菜单,并且不包含子菜单,具体来说:

LEVEL      PARENT_MENU_ID MENU_ID    MENU                 PERMISSION_ID 
---------- -------------- ---------- -------------------- ------------- 
         1                      1001 Menu C                            
         2           1001          1 -Menu C-A                       10
         2           1001       1003 -Menu C-G                         
         3           1003          6 --Menu C-G-B                    11
         1                      2001 Menu D                            
         2           2001         17 -Menu D-A                       14
         2           2001         18 -Menu D-B                       15

我如何做到这一点?

【问题讨论】:

  • Menu A-A : 10 is a child of Menu C 如何在您的预期输出中最终成为 Menu A 的孩子? Menu C 不应该也出现在permission_id = 11 中吗?
  • 谢谢 Nicholas Krasnov,你是对的,在我试图用名称显示结构的菜单名称中有错字,即菜单 C 应该被称为菜单 A,反之亦然 - 我认为 - 会在时间允许的情况下更正它(现在赶飞机)。
  • 更正数据,使查询显示菜单结构并简化问题。感谢 Nicholas Krasnov 的意见。

标签: sql oracle menu tree hierarchical


【解决方案1】:

您只需从感兴趣的节点(在本例中为权限为 10、11、14 和 15 的节点)遍历树,直至其根节点。在该问题的先前版本之一中有一个查询可以执行此操作。如果您运行的是 Oracle 11g 及更高版本,您可以使用 connect by 或递归公用表表达式:

使用connect by

select distinct
       menu_id
     , parent_menu_id
     , menu_name
     , permission_id
  from menu m
  start with permission_id in (10, 11, 14, 15)
  connect by prior parent_menu_id = menu_id
  order by nvl(parent_menu_id, menu_id), menu_name


  MENU_ID PARENT_MENU_ID MENU_NAME            PERMISSION_ID
---------- -------------- -------------------- -------------
      1001                Menu C                            
         1           1001 Menu C-A                        10
      1003           1001 Menu C-G                          
         6           1003 Menu C-G-B                      11
      2001                Menu D                            
        17           2001 Menu D-A                        14
        18           2001 Menu D-B                        15

递归 CTE:

with menus(menu_id, parent_menu_id, menu_name, permission_id, lv) as(
  select menu_id, parent_menu_id, menu_name, permission_id, 0
    from menu
   where permission_id in (10,11,14, 15)
   union all
   select m.menu_id, m.parent_menu_id, m.menu_name, m.permission_id, lv + 1
     from menu m
          join menus m2
            on (m.menu_id = m2.parent_menu_id)
)
select distinct 
       parent_menu_id
     , menu_id
     , menu_name
     , permission_id
  from menus 
order by nvl(parent_menu_id, menu_id), menu_name


PARENT_MENU_ID    MENU_ID MENU_NAME            PERMISSION_ID
-------------- ---------- -------------------- -------------
                     1001 Menu C                            
          1001          1 Menu C-A                        10
          1001       1003 Menu C-G                          
          1003          6 Menu C-G-B                      11
                     2001 Menu D                            
          2001         17 Menu D-A                        14
          2001         18 Menu D-B                        15

【讨论】:

    猜你喜欢
    • 2014-03-15
    • 2013-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多