来自join的oracle层次结构查询start子句

时间:2016-01-28 16:14:03

标签: sql oracle

我有一个包含文件夹user_rights的表。考虑到权限是在文件夹层次结构上继承的,在文件夹上右键对任何子文件夹赋予权限。

RIGHTS:
USERID     FOLDERID
---------------------  
685        5534      
685        5538      
686        5162      
686        6343      
686        28568     
686        41578     
725        113867    
725        127030    
FOLDERS:
FOLDERID     PARENTFOLDERID
----------------------------  
5534      
5538         5534
5162         5534      
6343         5162      
28568        5162     
41578        5534     
113867       41578    
127030       41578    

我需要一个包含所有用户/文件夹权限的列表。我尝试在start子句中使用带有连接的分层查询,如下所示:

select 
from rights r, 
(select f.folder_id from folders f
 start with f.folder_id = r.folder_id
 connect by prior f.folder_id = f.parent_id)

但不接受出站参考 r.folder_id

2 个答案:

答案 0 :(得分:1)

您的r别名及其引用的rights表不在您正在创建的内联视图的范围内。您需要生成层次结构,您仍然可以在内联视图中执行该层次结构,然后通过其rights将其加入folderid表。

您可以从以下位置获取层次结构:

select connect_by_root(folderid) as rootid, folderid,
  sys_connect_by_path(folderid, '/') as path
from folders
connect by parentfolderid = prior folderid
order by rootid, path;

    ROOTID   FOLDERID PATH                         
---------- ---------- ------------------------------
      5162       5162 /5162                         
      5162      28568 /5162/28568                   
      5162       6343 /5162/6343                    
      5534       5534 /5534                         
      5534      41578 /5534/41578                   
      5534     113867 /5534/41578/113867            
      5534     127030 /5534/41578/127030            
      5534       5162 /5534/5162                    
      5534      28568 /5534/5162/28568              
      5534       6343 /5534/5162/6343               
      5534       5538 /5534/5538                    
      5538       5538 /5538                         
...

这几乎就是你正在做的事情,但是这会从任何起点找到所有后代,并且还将起点捕获为rootid。 (我已经在path中抛出了只是为了可视化层次结构;你似乎不希望在结果中出现这种情况。)

然后,您可以将其加入权利表,其中每个用户的folderid都与rootid匹配。这将列出重复项(例如685可以直接或通过5534到达5538),因此您可以使用distinct来消除这些:

select distinct r.userid, f.folderid
from rights r
join (
  select connect_by_root(folderid) as rootid, folderid
  from folders
  connect by prior folderid = parentfolderid
) f
on f.rootid = r.folderid
order by r.userid, f.folderid;

与您的数据相关的是16个不同的组合:

    USERID   FOLDERID
---------- ----------
       685       5162
       685       5534
       685       5538
       685       6343
       685      28568
       685      41578
       685     113867
       685     127030
       686       5162
       686       6343
       686      28568
       686      41578
       686     113867
       686     127030
       725     113867
       725     127030

您也可以使用recursive subquery factoring代替分层查询:

with rcte (userid, folderid) as (
  select r.userid, f.folderid
  from rights r
  join folders f on f.folderid = r.folderid
  union all
  select rcte.userid, f.folderid
  from rcte
  join folders f on f.parentfolderid = rcte.folderid
)
select distinct userid, folderid
from rcte
order by userid, folderid;

锚成员是两个表之间的简单连接,以获得顶级权限。然后递归成员查找已找到的任何子权限。结果相同,方法略有不同。

答案 1 :(得分:1)

您可以使用Oracle 12c中引入的CROSS APPLYOUTER APPLY运算符执行您尝试的操作。 CROSS/OUTER APPLY运算符允许您创建相关联接。不幸的是我现在没有12c实例可以使用,所以这是在旧版本的oracle中实现它的一种方法。我们的想法是在您加入数据后将层次结构部分移动到:

with j as (
  select userid, folderid, parentfolderid
    from rights natural join folders
)
select CONNECT_BY_ROOT userid userid
     , folderid
     , SYS_CONNECT_BY_PATH(folderid, '/') folder_path
     , row_number() over (partition by CONNECT_BY_ROOT userid, folderid 
                              order by level desc) rn
  from j
  connect by prior folderid = parentfolderid
 order by userid, folderid;

我在输出中包含了RN行号列,以帮助显示层次结构中给定用户多次包含哪些文件夹。任何大于1的值都表示已通过直接授权覆盖了继承的权限。

    USERID   FOLDERID FOLDER_PATH                            RN
---------- ---------- ------------------------------ ----------
       685       5162 /5534/5162                              1
       685       5534 /5534                                   1
       685       5538 /5534/5538                              1
       685       5538 /5538                                   2
       685       6343 /5534/5162/6343                         1
       685      28568 /5534/5162/28568                        1
       685      41578 /5534/41578                             1
       685     113867 /5534/41578/113867                      1
       685     127030 /5534/41578/127030                      1
       686       5162 /5162                                   1
       686       6343 /5162/6343                              1
       686       6343 /6343                                   2
       686      28568 /5162/28568                             1
       686      28568 /28568                                  2
       686      41578 /41578                                  1
       686     113867 /41578/113867                           1
       686     127030 /41578/127030                           1
       725     113867 /113867                                 1
       725     127030 /127030                                 1

 19 rows selected