Reputation: 185
I am trying to create an employee org hierarchy using Access 2010. My basic table contains information about the employee, including their direct manager. Ideally, I'd like to create a single table that contains every level of reporting. The net output of this query would be a table that contains the owner, the owned, and the depth of the relationship between the owner and the owned.
My data table can be summarized down to:
Owned EE ID
Direct Owner ID
The net output I'd like to create is a table like this:
Owner | Owned | Levels between Owner and Owned
As an example, suppose John reports into Joe who reports into Jane. My structure would then be:
Joe | John | 1
Jane | Joe | 1
Jane | John | 2
I know that I will not go more than 11 levels deep between the top of my tree (the CEO) and the bottom of my tree (hourly worker peon).
Is such a thing possible to do in Access SQL? Ideally I'd prefer not to write a macro but I will if I have to. I can build from the bottom up or the top down, I really don't care, but I built my test file in Excel from the top down, and it's easier to start top down, since I'd start with the EE who does not have a direct manager (the CEO).
I am a relative n00b to Access, if that matters. Thank you.
Upvotes: 1
Views: 3995
Reputation: 123779
Access SQL does not support recursion (like recursive CTEs in SQL Server), but the following VBA code will take an input table named [Employees]...
ID EmployeeName ReportsTo
-- ------------ ---------
1 Jane
2 Joe 1
3 John 2
4 Julia 2
5 Jack 4
6 Jimbo 2
7 Jill 5
...and populate a table named [EmployeeHierarchy]...
Superior Subordinate LevelDifference
-------- ----------- ---------------
Jane Joe 1
Joe John 1
Jane John 2
Joe Julia 1
Jane Julia 2
Julia Jack 1
Joe Jack 2
Jane Jack 3
Jack Jill 1
Julia Jill 2
Joe Jill 3
Jane Jill 4
Joe Jimbo 1
Jane Jimbo 2
...like so:
Option Compare Database
Option Explicit
Sub OrgTree()
Dim cdb As DAO.Database, rstTop As DAO.Recordset
Set cdb = CurrentDb
cdb.Execute "DELETE FROM EmployeeHierarchy", dbFailOnError
Set rstTop = cdb.OpenRecordset( _
"SELECT ID, EmployeeName " & _
"FROM Employees " & _
"WHERE ReportsTo IS NULL", _
dbOpenSnapshot)
' process each top-level entity
Do While Not rstTop.EOF
ProcessSubordinates rstTop!ID, rstTop!EmployeeName, 0
rstTop.MoveNext
Loop
rstTop.Close
Set rstTop = Nothing
Set cdb = Nothing
End Sub
Sub ProcessSubordinates(BaseID As Long, BaseName As String, RecursionLevel As Long)
Dim rstSubs As DAO.Recordset
Dim i As Long, CurrentID As Long, SuperiorID As Long, SuperiorName As String
Set rstSubs = CurrentDb.OpenRecordset( _
"SELECT ID, EmployeeName " & _
"FROM Employees " & _
"WHERE ReportsTo = " & BaseID, _
dbOpenSnapshot)
' loop through immediate subordinates for the "base" employee
Do While Not rstSubs.EOF
AddToEmployeeHierarchy BaseName, rstSubs!EmployeeName, 1
' traverse back up the tree to list all other superiors
CurrentID = BaseID
For i = 1 To RecursionLevel
SuperiorID = DLookup("ReportsTo", "Employees", "ID = " & CurrentID)
SuperiorName = DLookup("EmployeeName", "Employees", "ID = " & SuperiorID)
AddToEmployeeHierarchy SuperiorName, rstSubs!EmployeeName, i + 1
CurrentID = SuperiorID
Next
' and recurse to process down the tree for the current subordinate
ProcessSubordinates rstSubs!ID, rstSubs!EmployeeName, RecursionLevel + 1
rstSubs.MoveNext
Loop
rstSubs.Close
Set rstSubs = Nothing
End Sub
Sub AddToEmployeeHierarchy(SuperiorName As String, SubordinateName As String, LevelDifference As Long)
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("EmployeeHierarchy", dbOpenTable)
rst.AddNew
rst!Superior = SuperiorName
rst!Subordinate = SubordinateName
rst!LevelDifference = LevelDifference
rst.Update
rst.Close
Set rst = Nothing
End Sub
Upvotes: 1