简体   繁体   English

如何转换具有层次结构的表?

[英]How to transform tables with hierarchy?

I have a table with two columns which looks like this我有一个有两列的表格,看起来像这样

在此处输入图片说明

I want to bring it to this format wherein all the User IDs under a manager's hierarchy are mapped which should like this.我想把它变成这种格式,其中映射了经理层次结构下的所有用户 ID,这应该是这样的。 If a user id does not have a manager id, then the same user id needs to be used as manager id如果用户 ID 没有经理 ID,则需要使用相同的用户 ID 作为经理 ID

在此处输入图片说明

Any help or even if I am pointed in the right direction will be extremely helpful.任何帮助或即使我指向正确的方向也将非常有帮助。 Thank you谢谢

It is just a classic case of recursion on a hierarchy:这只是一个层次结构递归的经典案例:

declare @table table (ManagerId int, userId int);
insert @table values 
    (4,1), (4,2), (4,3), -- report to 4
    (5,4), -- report to 5
    (6,5), -- report to 6
    (7,6); -- report to 7

with traverse as (

    select     managerId, userId
    from       @table t

    -- Union all in a cte selecting from 
    -- the cte itself initiates recursion.
    union all  
    select     nxt.managerId, cur.userId
    from       traverse cur
    join       @table nxt on cur.managerId = nxt.userId 
    where      nxt.managerId is not null
)


select     isnull(managerId, userId) managerId, userId
from       traverse             
order by   managerId, userId
option     (maxrecursion 1000) -- change if you're getting a max recursion error

I see there has been a lot of progress while I was working on a solution for you.我看到在我为您制定解决方案的过程中取得了很大进展。 It may not have adapted to the latest changes.它可能没有适应最新的变化。 Please take a look.请看一下。

Option Explicit

Enum Nws                        ' worksheet locations
    NwsFirstDataRow = 2
    NwsStaff = 1                ' 1 = column A
    NwsSuper                    ' no value = (preceding + 1)
                                ' the above columns need not be adjecent
    NwsManager = 5              ' { blank columns for output
    NwsUserID                   ' { function as your sample
End Enum

Sub SortHierarchy()
    ' Variatus @STO 12 Mar 2020

    Dim Rng As Range
    Dim Arr As Variant
    Dim i As Long                           ' index to Arr()
    Dim StaffID As Variant                  ' can be alphanumeric
    Dim Rl As Long                          ' last row
    Dim R As Long                           ' current row
    Dim Spike() As String
    Dim n As Long                           ' index to Spike()
    Dim Sp() As String                      ' split of Spike(n)


    Application.ScreenUpdating = False

    With Worksheets("Sheet1")               ' modify tab name
        Rl = .Cells(.Rows.Count, NwsStaff).End(xlUp).Row
        ' both columns should be of equal length
        Set Rng = .Range(.Cells(NwsFirstDataRow, NwsStaff), _
                         .Cells(Rl, NwsSuper))
        SortData Rng, NwsSuper
        Arr = Rng.Columns(NwsSuper).Value
        ReDim Spike(UBound(Arr) - 1)

        For R = NwsFirstDataRow To Rl
            StaffID = .Cells(R, NwsStaff).Value
            n = R - NwsFirstDataRow
            Spike(n) = StaffID
            For i = 1 To UBound(Arr)
                If Arr(i, 1) >= StaffID Then
                    Spike(n) = Spike(n) & "," & .Cells(i + 1, NwsStaff).Value
                End If
            Next i
        Next R

        .Columns(NwsManager).Resize(, 2).ClearContents
        .Cells(1, NwsManager).Value = "Manager"
        .Cells(1, NwsUserID).Value = "UserID"
        R = NwsFirstDataRow

        For n = 0 To UBound(Spike)
            Sp = Split(Spike(n), ",")

            For i = 0 To UBound(Sp)
                If Len(Sp(i)) = 0 Then Exit For

                If Sp(i) <> Sp(0) Then
                    .Cells(R, NwsManager).Value = Sp(0)
                    .Cells(R, NwsUserID).Value = Sp(i)
                    R = R + 1
                End If
            Next i
        Next n

        Rl = .Cells(.Rows.Count, NwsManager).End(xlUp).Row
        Set Rng = .Range(.Cells(NwsFirstDataRow, NwsManager), _
                         .Cells(Rl, NwsUserID))
    End With
    SortData Rng

    Application.ScreenUpdating = True
End Sub

Private Sub SortData(Rng As Range, _
                     Optional ByVal SortColumn As Nws)

    With Rng.Worksheet.Sort
        With .SortFields
            .Clear
            If (SortColumn = NwsStaff) Or (SortColumn = 0) Then
                .Add Key:=Rng.Columns(NwsStaff), SortOn:=xlSortOnValues, _
                     Order:=xlAscending, DataOption:=xlSortNormal
            End If
            If (SortColumn = NwsSuper) Or (SortColumn = 0) Then
                .Add Key:=Rng.Columns(NwsSuper), SortOn:=xlSortOnValues, _
                     Order:=xlAscending, DataOption:=xlSortNormal
            End If
        End With
        .SetRange Rng
        .Header = xlNo
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
End Sub

This code will run on a worksheet called "Sheet1" (amend in procedure SortHierarchy ) and requires data in columns A and B (amend in the Enum at the top of the code. Run the procedure SortHierarchy .此代码将在名为“Sheet1”的工作表上运行(在过程SortHierarchy修改)并需要 A 列和 B 列中的数据(在代码顶部的 Enum 中修改。运行过程SortHierarchy

My data in columns A and B might differ from yours.我在 A 列和 B 列中的数据可能与您的不同。 For my own clarity I called the columns "StaffID" and "ReportsTo".为清楚起见,我将这些列称为“StaffID”和“ReportsTo”。 In principle every staff member reports to somebody.原则上每个工作人员都向某人报告。 Therefore column A may hold a list of all staff members.因此,A 列可能包含所有工作人员的列表。 The applied logic is that if the worker reports to the supervisor, the supervisor to the manager and the manager to the boss, then worker, supervisor and manager all report to the boss.应用的逻辑是,如果工人向主管报告,主管向经理报告,经理向老板报告,那么工人、主管和经理都向老板报告。 The boss reports to nobody which is to say himself.老板向任何人报告,也就是他自己。 The same status can be allocated to any staff member.可以将相同的状态分配给任何员工。 It's also possible to let a worker report directly to the boss.也可以让工人直接向老板汇报。 All of this is expressed in the two columns "StaffID" and 'ReportsTo".所有这些都在“StaffID”和“ReportsTo”两列中表达。

The macro takes these data and sorts them into a hierarchical list which is written to two blank columns on the same worksheet.宏获取这些数据并将它们分类到一个分层列表中,该列表写入同一工作表上的两个空白列。 You can assign the columns in the Enum.您可以分配枚举中的列。 Note that the macro will allow for data between the columns A and B (which are freely assignable) and those data would stay aligned with the data being sorted.请注意,宏将允许 A 列和 B 列(可自由分配)之间的数据,并且这些数据将与正在排序的数据保持一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM