我有下一张桌子.groups表包含按层次排序的组和group_member,用于存储用户所属的组.
groups
---------
id
parent_id
name
group_member
---------
id
group_id
user_id
ID PARENT_ID NAME
---------------------------
1 NULL Cerebra
2 1 CATS
3 2 CATS 2.0
4 1 Cerepedia
5 4 Cerepedia 2.0
6 1 CMS
ID GROUP_ID USER_ID
---------------------------
1 1 3
2 1 4
3 1 5
4 2 7
5 2 6
6 4 6
7 5 12
8 4 9
9 1 10
Run Code Online (Sandbox Code Playgroud)
我想检索给定用户的可见组.这就是说用户属于的组和这些组的子组.例如,使用以上数据:
USER VISIBLE_GROUPS
9 4, 5
3 1,2,4,5,6
12 5
Run Code Online (Sandbox Code Playgroud)
我使用递归和几个数据库查询获取这些值.但我想知道是否可以使用单个SQL查询来提高我的应用程序性能.我正在使用MySQL.
我想到两件事:
1 -您可以反复将表外连接到自身,以递归方式向上走树,如下所示:
SELECT *
FROM
MY_GROUPS MG1
,MY_GROUPS MG2
,MY_GROUPS MG3
,MY_GROUPS MG4
,MY_GROUPS MG5
,MY_GROUP_MEMBERS MGM
WHERE MG1.PARENT_ID = MG2.UNIQID (+)
AND MG1.UNIQID = MGM.GROUP_ID (+)
AND MG2.PARENT_ID = MG3.UNIQID (+)
AND MG3.PARENT_ID = MG4.UNIQID (+)
AND MG4.PARENT_ID = MG5.UNIQID (+)
AND MGM.USER_ID = 9
Run Code Online (Sandbox Code Playgroud)
那会给你这样的结果:
UNIQID PARENT_ID NAME UNIQID_1 PARENT_ID_1 NAME_1 UNIQID_2 PARENT_ID_2 NAME_2 UNIQID_3 PARENT_ID_3 NAME_3 UNIQID_4 PARENT_ID_4 NAME_4 UNIQID_5 GROUP_ID USER_ID
4 2 Cerepedia 2 1 CATS 1 null Cerebra null null null null null null 8 4 9
Run Code Online (Sandbox Code Playgroud)
这里的限制是您必须为要在树上行走的每个"级别"添加新的连接.如果你的树的数量少于20级,那么你可以通过创建一个显示每个用户20个级别的视图来逃避它.
2 -我所知道的唯一其他方法是创建递归数据库函数,并从代码中调用它.你仍然会有一些查询开销(也就是说,你的#查询仍然等于你在树上行走的等级数),但总体来说它应该更快,因为它全部发生在数据库中.
我不确定MySql,但在Oracle中,这样的函数与此类似(你必须更改表和字段名称;我只是复制我过去做过的事情):
CREATE OR REPLACE FUNCTION GoUpLevel(WO_ID INTEGER, UPLEVEL INTEGER) RETURN INTEGER
IS
BEGIN
DECLARE
iResult INTEGER;
iParent INTEGER;
BEGIN
IF UPLEVEL <= 0 THEN
iResult := WO_ID;
ELSE
SELECT PARENT_ID
INTO iParent
FROM WOTREE
WHERE ID = WO_ID;
iResult := GoUpLevel(iParent,UPLEVEL-1); --recursive
END;
RETURN iResult;
EXCEPTION WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
END GoUpLevel;
/
Run Code Online (Sandbox Code Playgroud)