[英]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.