我有一个带有两列的表,看起来像这样
我想将其转换为这种格式,在这种格式下,经理层次结构下的所有用户ID都应该映射。如果用户ID没有管理员ID,则需要使用相同的用户ID作为管理员ID
任何帮助,即使我的方向正确,也将非常有帮助。谢谢
答案 0 :(得分:0)
这只是在层次结构上进行递归的经典案例:
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
答案 1 :(得分:0)
当我为您设计解决方案时,我看到了很大的进步。它可能未适应最新的更改。请看看。
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
此代码将在名为“ Sheet1”的工作表上运行(在过程SortHierarchy
中进行修改),并且需要A和B列中的数据(在代码顶部的Enum中进行修改。运行过程{{1 }}。
我在A和B列中的数据可能与您的数据不同。为清楚起见,我将列称为“ StaffID”和“ ReportsTo”。原则上,每个员工都向某人报告。因此,A列可能包含所有工作人员的列表。应用的逻辑是,如果工人向主管报告,主管向经理报告,经理向老板报告,那么工人,主管和经理都向老板报告。老板不向任何人报告,也就是说他自己。可以向任何工作人员分配相同的身份。也可以让工人直接向老板汇报。所有这些都在“ StaffID”和“ ReportsTo”两列中表示。
宏将这些数据收集并分类到一个层次列表中,该列表被写入同一工作表上的两个空白列中。您可以在Enum中分配列。请注意,该宏将允许在A和B列之间的数据(可自由分配),并且这些数据将与正在排序的数据保持一致。