Re: Modelling hierarchy in the relational database
Date: Tue, 04 Sep 2001 08:23:43 GMT
Message-ID: <jc0l7.2934$4z.4263_at_www.newsranger.com>
In article <ER_k7.2904$4z.4167_at_www.newsranger.com>, Vadim Tropashko says...
>Try printing out hierarchy like this:
>
>EMPNAME DNAME CBP
>------------------------------ -------------- ------------------------------
>**KING ACCOUNTING /KING
>****BLAKE SALES /KING/BLAKE
>******ALLEN SALES /KING/BLAKE/ALLEN
>******JAMES SALES /KING/BLAKE/JAMES
>******MARTIN SALES /KING/BLAKE/MARTIN
>******TURNER SALES /KING/BLAKE/TURNER
>******WARD SALES /KING/BLAKE/WARD
>
>with nested sets.
It can be done as follows. First, we need to build a view of each employee with names of their manager as a path like this:
SQL> SELECT P1.emp, P2.emp path, indentation
2 FROM Personnel_tree P1, Personnel_tree P2, 3 (SELECT count(P2.emp) indentation, P1.emp 4 FROM Personnel_tree P1, Personnel_tree P2 5 WHERE P1.lft BETWEEN P2.lft AND P2.rgt 6 GROUP BY P1.emp) counter
7 WHERE P1.lft BETWEEN P2.lft AND P2.rgt 8 and counter.emp = P2.emp
9 order by P1.emp, indentation;
EMP PATH INDENTATION
---------- ---------- -----------
Albert Albert 1 Bert Albert 1 Bert Bert 2 Chuck Albert 1 Chuck Chuck 2 Donna Albert 1 Donna Chuck 2 Donna Donna 3 Eddie Albert 1 Eddie Chuck 2 Eddie Eddie 3 Fred Albert 1 Fred Chuck 2 Fred Fred 3
The above query is no more than just a combination of Joe Celko's #1 and #4 "basic" queries.
Second, we need to group by the first column and use a concatenation function to aggregate by the second column (and ignore the third one as it is needed for ordering names in the path only). The query
select concat(path, '/') from (
SELECT P1.emp, P2.emp path
FROM Personnel_tree P1, Personnel_tree P2,
(SELECT count(P2.emp) indentation, P1.emp
FROM Personnel_tree P1, Personnel_tree P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
GROUP BY P1.emp) counter
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
and counter.emp = P2.emp
order by P1.emp, indentation
) group by emp
could be executed by RDBMS supporting user-defined aggregates only, of course.
Finally, using your technique
http://www.oracle.com/oramag/code/tips2001/index.html?052001.html
the query with user-defined aggregate could be implemented as:
SQL> SELECT CONCAT_LIST(EMPLS, '/') EMPLOYEES from (
2 SELECT 3 emp, 4 CAST(MULTISET(SELECT P2.emp 5 FROM Personnel_tree P1, Personnel_tree P2, 6 (SELECT count(P2.emp) indentation, P1.emp 7 FROM Personnel_tree P1, Personnel_tree P2 8 WHERE P1.lft BETWEEN P2.lft AND P2.rgt 9 GROUP BY P1.emp) counter 10 WHERE P1.lft BETWEEN P2.lft AND P2.rgt 11 and counter.emp = P2.emp 12 and p1.emp = a.emp 13 order by indentation 14 ) 15 AS string_list_t) EMPLS 16 FROM Personnel_tree a 17 group by emp
18 );
EMPLOYEES
/Albert /Albert /Bert /Albert /Chuck /Albert /Chuck /Donna /Albert /Chuck /Eddie /Albert /Chuck /FredReceived on Tue Sep 04 2001 - 10:23:43 CEST