2016-12-07 3 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 
/

Giving:

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' является child из 'Menu C', как именно он оказался ребенком« Menu A »в вашем ожидаемом выходе? Не следует ли «Меню C» присутствовать также для 'permission_id = 11'? –

+0

Спасибо Николаю Краснову, вы правы, опечатались в именах меню, где я попытался показать структуру с именами, то есть меню C нужно было назвать Меню А, и наоборот - я думаю - будет исправлять его, когда позволяет время (из теперь поймать рейс). – VinceJS

+0

Исправленные данные, сделанный запрос показывают структуру меню и упрощают вопрос. Спасибо Николаю Краснову за ваш вклад. – 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 
Смежные вопросы