我有一个包含文件夹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 。
答案 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 APPLY
或OUTER 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