На ум приходят две вещи:
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
Это даст вам такие результаты:
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
Пределом здесь является то, что вы должны добавить новое объединение для каждого "уровня", который вы хотите пройти по дереву. Если ваше дерево имеет, скажем, менее 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;
/