Hi,
If the tree is relatively stable, you can use a nested set
representation. Basically, a nested set representation has nodes with two
values, lft and rgt (left and right, but since those are reserved
words...). You start worm (counter) =1, and make the "actual node under
consideration" the big boss,
1- for the actual node, lft=worm; worm = worm+1;
2- If the actual node has children with their rgt empty, take one of them as
the actual node, goto 1
3- if the actual node has no children left with their rgt empty, mark the
actual node rgt=worm; then make worm=worm+1; then, make its parent as the
actual node, goto 2
4- sure, if steps 3 find the actual node without parent, you are done the
labeling of lft and rgt values.
Example: A has B, C and D as children. B has E and F while C and G and F
has H:
A.lft=1
B.lft=2
E.lft=3
E.rgt=4
F.lft =5
H.lft=6
H.rgt=7
F.rgt=8
B.rgt=9
C.lft=10
G.lft=11
G.rgt=12
C.rgt=13
D.lft=14
D.rgt=15
A.rgt=16
Once we have the lft and rgt values, among other interesting properties:
we can get all the nodes under X by:
SELECT *
FROM Nodes
WHERE Nodes.lft BETWEEN X.lft AND X.rgt
We can get all the boss of X with
SELECT *
FROM Nodes
WHERE X.lft BETWEEN Nodes.lft AND Nodes.rgt
The "level" of node X
SELECT COUNT(*)
FROM Nodes
WHERE X.lft BETWEEN Nodes.lft AND Nodes.rgt
How many nodes there is under X
(1+X.rgt-X.lft)/2
If a node is a terminal (leaf):
rgt=lft+1
Those quite simple statements work whatever the number of levels there can
be in the tree... thanks to the "precompiled" values lft and rgt.
Hoping it may help,
Vanderghast, Access MVP
baphensley said:
MW and SC,
Thanks for the help.
I finally came to a similar conclusion.
Unfortunately, the number of levels is not consistent. But, I can
estimate a maximum number of levels; so I was able to use a string of
self joins that went deeper than the lowest level. This succeeded
(though I'm sure can be done much cleaner).
Here is a parameter query to find all staff under a boss, not matter
how far down the tree (as long as it's no more than 6 levels) ...
SELECT tblStaff.StaffID, [tblStaff]![StaffID] & " " &
[tblStaff]![ReportsToID] & " " & [B2]![ReportsToID] & " " &
[B3]![ReportsToID] & " " & [B4]![ReportsToID] & " " &
[B5]![ReportsToID] AS ChainOCmd
FROM ((((tblStaff LEFT JOIN tblStaff AS B1 ON tblStaff.ReportsToID =
B1.StaffID) LEFT JOIN tblStaff AS B2 ON B1.ReportsToID = B2.StaffID)
LEFT JOIN tblStaff AS B3 ON B2.ReportsToID = B3.StaffID) LEFT JOIN
tblStaff AS B4 ON B3.ReportsToID = B4.StaffID) LEFT JOIN tblStaff AS B5
ON B4.ReportsToID = B5.StaffID
WHERE ((([tblStaff]![StaffID] & " " & [tblStaff]![ReportsToID] & " " &
[B2]![ReportsToID] & " " & [B3]![ReportsToID] & " " &
[B4]![ReportsToID] & " " & [B5]![ReportsToID]) Like "*" & [Boss: ] &
"*"));
Thanks again,
Bruce