Reputation: 1281
I am trying to create an organizational structure using LEVEL
functionality in Oracle11g.
I have the following query:
SELECT
level,
lpad(' ', 3 * (level - 1)) || em.empno || ' : ' || em.fname || ' ' || em.lname "Employee",
em.position "Position",
outno || ': ' || ou.street || ' ' || ou.city || ' ' || ou.zipcode "Outlet",
count(DISTINCT fa.reportnum) "# of Fault Reports"
FROM employee em
INNER JOIN outlet ou USING (outno)
LEFT JOIN faultreport fa ON fa.empno = em.empno AND fa.datechecked > (SYSDATE - 91)
START WITH em.empno = 30012
CONNECT BY PRIOR em.empno = em.supervisorno
GROUP BY level,
em.empno, em.fname, em.lname, em.position,
outno, ou.street, ou.city, ou.zipcode;
Which gives me the following output:
LEVEL Employee Position Outlet # of Fault Reports
----- --------------------------------- -------------------- ------------------------------ ------------------
1 30012 : Moreno Bale Owner 119: Forrest Adelaide 5005 0
2 45611 : Annah Marlek Area_Manager 112: Beauford Port Cambia 5001 0
2 48900 : Geoff Hanna Area_Manager 118: Icecream Iyanee 5008 0
3 23490 : Abel Cole Admin_Assistant 116: Huntington Banshee 5007 0
3 31459 : Chris Boss Admin_Assistant 119: Forrest Adelaide 5005 0
3 60021 : Beau Rueford Admin_Assistant 111: Junlee Caprice 5009 0
3 67823 : Jess Fred Head_Mechanic 114: Elephant Ocupus 5004 0
4 55601 : Kabil Malla Mechanic 115: Dundee Eeyrie 5003 1
4 55602 : Harry Potter Mechanic 111: Junlee Caprice 5009 5
4 60020 : Maria Marbosa Sales_Rep 113: Cathany Zeus 5002 0
4 77689 : Javier Martin Sales_Rep 112: Beauford Port Cambia 5001 0
11 rows selected.
However, when I see the table, this is the exact relationship:
Employee Manager
30012 -
48900 30012
45611 30012
23490 45611
31459 48900
67823 48900
55602 67823
55601 67823
60021 48900
77689 60021
60020 60021
How do I implement this in Oracle so that I have the following output:
LEVEL Employee Position Outlet # of Fault Reports
----- --------------------------------- -------------------- ------------------------------ ------------------
1 30012 : Moreno Bale Owner 119: Forrest Adelaide 5005 0
2 45611 : Annah Marlek Area_Manager 112: Beauford Port Cambia 5001 0
3 23490 : Abel Cole Admin_Assistant 116: Huntington Banshee 5007 0
2 48900 : Geoff Hanna Area_Manager 118: Icecream Iyanee 5008 0
3 31459 : Chris Boss Admin_Assistant 119: Forrest Adelaide 5005 0
3 60021 : Beau Rueford Admin_Assistant 111: Junlee Caprice 5009 0
4 60020 : Maria Marbosa Sales_Rep 113: Cathany Zeus 5002 0
4 77689 : Javier Martin Sales_Rep 112: Beauford Port Cambia 5001 0
3 67823 : Jess Fred Head_Mechanic 114: Elephant Ocupus 5004 0
4 55601 : Kabil Malla Mechanic 115: Dundee Eeyrie 5003 1
4 55602 : Harry Potter Mechanic 111: Junlee Caprice 5009 5
11 rows selected.
Note that the if a manager manages more than 1 employee, then the tree is expanded based on employee number.
Thanks!
Upvotes: 3
Views: 73
Reputation: 2450
The explanation of your data lacks of many details. Anyway by the query you tried to execute and your excepted output, I suppose that the mistake was that you tried to do to many things at once: aggregation and hierarchical query together.
To get your desired output the connect by should be the last step of the query evaluation, but the aggregation can't be evaluated before it in a query.
The connect by evaluation returns rows in your expected order, but the grouping clause, witch defines an implicit sort in its evaluation, overrides it giving the rows ordered by the grouping keys.
Generally SQL statements processing evaluates query clauses in the following order:
So you should separate the two things through a subquery that evaluates the count aggregation before executing the hierarchical query phase without sorting the output.
You may try this query:
SELECT LEVEL, LPAD(' ', 3*(LEVEL - 1)) || empno || ' : ' || EM.fname || ' ' || EM.lname "Employee",
EM.position "Position", outno || ': ' || OU.street || ' ' || OU.city || ' ' || OU.zipcode "Outlet",
dist_reportnums "# of Fault Reports"
FROM employee EM
JOIN outlet OU using (outno)
LEFT JOIN (
selec empno, COUNT(DISTINCT FA.reportnum) as dist_reportnums
from faultreport FA
where FA.datechecked > (SYSDATE - 91)
GROUP BY empno
) using (empno)
START WITH empno = 30012
CONNECT BY PRIOR empno = EM.supervisorno
Upvotes: 3