Question

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.

Était-ce utile?

La solution

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top