2016-12-07 28 views
2

有一個菜單表:如何處理我的Oracle層級菜單查詢中的權限?

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 

我該如何做到這一點?

+0

'菜單AA:10'是「菜單C」的孩子在你期望的輸出中究竟是「菜單A」的孩子? ''C'不應該''permission_id = 11'出現? –

+0

謝謝尼古拉斯克拉斯諾夫,你是正確的,菜單名稱中的錯字,我嘗試用名稱顯示結構,即菜單C應該被稱爲菜單A,反之亦然 - 我認爲 - 如果時間允許,現在趕上航班)。 – VinceJS

+0

更正後的數據,使查詢顯示菜單結構並簡化問題。謝謝Nicholas Krasnov的意見。 – VinceJS

回答

0

您只需從您感興趣的節點(本例中爲權限爲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