Вопрос

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.

Это было полезно?

Решение

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top