我只有大约 1000 到 2000 个左右的单元格,所以我最终在这里使用了 Jerry 的级联树公式
https://sites.google.com/a/madrocketscientist.com/jerrybeaucaires-excelassistant/text-functions/cascading-tree
Option Explicit
Sub TreeStructure()
'JBeaucaire 3/6/2010, 10/25/2011
'Create a flow tree from a two-column accountability table
Dim LR As Long, NR As Long, i As Long, Rws As Long
Dim TopRng As Range, TopR As Range, cell As Range
Dim wsTree As Worksheet, wsData As Worksheet
Application.ScreenUpdating = False
'Find top level value(s)
Set wsData = Sheets("Input")
'create a unique list of column A values in column M
wsData.Range("A:A").AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=wsData.Range("M1"), Unique:=True
'Find the ONE value in column M that reports to no one, the person at the top
wsData.Range("N2", wsData.Range("M" & Rows.Count).End(xlUp) _
.Offset(0, 1)).FormulaR1C1 = "=IF(COUNTIF(C2,RC13)=0,1,"""")"
Set TopRng = wsData.Columns("N:N").SpecialCells(xlCellTypeFormulas, 1).Offset(0, -1)
'last row of persons listed in data table
LR = wsData.Range("A" & wsData.Rows.Count).End(xlUp).Row
'Setup table
Set wsTree = Sheets("LEVEL STRUCTURE")
With wsTree
.Cells.Clear 'clear prior output
NR = 3 'next row to start entering names
'Parse each run from the top level
For Each TopR In TopRng 'loop through each unique column A name
.Range("B" & NR) = TopR
Set cell = .Cells(NR, .Columns.Count).End(xlToLeft)
Do Until cell.Column = 1
'filter data to show current leader only
wsData.Range("A:A").AutoFilter Field:=1, Criteria1:=cell
'see how many rows this person has in the table
LR = wsData.Range("A" & Rows.Count).End(xlUp).Row
If LR > 1 Then
'count how many people report to this person
Rws = Application.WorksheetFunction.Subtotal(103, wsData.Range("B:B")) - 1
'insert that many blank rows below their name and insert the names
cell.Offset(1, 1).Resize(Rws).EntireRow.Insert xlShiftDown
wsData.Range("B2:B" & LR).Copy cell.Offset(1, 1)
'add a left border if this is the start of a new "group"
If .Cells(.Rows.Count, cell.Column + 1).End(xlUp).Address _
<> cell.Offset(1, 1).Address Then _
.Range(cell.Offset(1, 1), cell.Offset(1, 1).End(xlDown)) _
.Borders(xlEdgeLeft).Weight = xlThick
End If
NR = NR + 1 'increment to the next row to enter the next top leader name
Set cell = .Cells(NR, .Columns.Count).End(xlToLeft)
Loop
Next TopR
'find the last used column
i = .Cells.Find("*", .Cells(.Rows.Count, .Columns.Count), _
SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'format the used data range
With Union(.Range(.[B1], .Cells(1, i)), .Range("B:BB").SpecialCells(xlCellTypeConstants, 23))
.Interior.ColorIndex = 5
.Font.ColorIndex = 2
.Font.Bold = True
.HorizontalAlignment = xlCenter
End With
.Range("B1").Interior.ColorIndex = 53
.Range("B1").Value = "LEVEL 1"
.Range("B1").AutoFill Destination:=.Range("B1", .Cells(1, i)), Type:=xlFillDefault
End With
wsData.AutoFilterMode = False
wsData.Range("M:N").ClearContents
wsTree.Activate
Application.ScreenUpdating = True
End Sub
这完成了我需要做的 95% 的工作,其余的我只使用了 excel 公式(之后不需要 VBA)
从头获取祖先数据的步骤:
我做了以下程序:
0:在关系数据设置中有数据
1:清除所有重复数据重复的条件格式
2:运行 Jerry 的 Excel VBA 宏。结果如下
Col A | ColB | ColC | ColD | ColE | ColF |
| Lvl1 | Lvl2 | Lvl3 | Lvl4 | Lvl5 |
| AAA | | | | |
| | BBB | | | |
| | EEE | | | |
| | FFF | | | |
| CCC | | | | |
| | GGG | | | |
| | | III | | |
| | | | JJJ | |
| | | | | KKK |
| DDD | | | | |
| | HHH | | | |
3:通过excel复制+粘贴的方式填充顶级excel(我只有3个父顶级类别,所以花了2分钟)
Col A | ColB | ColC | ColD | ColE | ColF |
| Lvl1 | Lvl2 | Lvl3 | Lvl4 | Lvl5 |
| AAA | | | | |
| AAA | BBB | | | |
| AAA | EEE | | | |
| AAA | FFF | | | |
| CCC | | | | |
| CCC | GGG | | | |
| CCC | | III | | |
| CCC | | | JJJ | |
| CCC | | | | KKK |
| DDD | | | | |
| DDD | HHH | | | |
4:然后通过此公式在 A 列中使用辅助列
=IF(B19<>"", B19,
IF(C19<>"",C19,
IF(D19<>"",D19,
IF(F19<>"",F19))))
其中 C、D、E、F 是源自父级的子类别级别(B 列)。这会搜索 C 列中的值作为输入,如果不存在,则搜索 D 列、E 列、F 列并复制它首先找到的任何内容。
Col A | ColB | ColC | ColD | ColE | ColF |
| Lvl1 | Lvl2 | Lvl3 | Lvl4 | Lvl5 |
| AAA | | | | |
BBB | AAA | BBB | | | |
EEE | AAA | EEE | | | |
FFF | AAA | FFF | | | |
| CCC | | | | |
GGG | CCC | GGG | | | |
III | CCC | | III | | |
JJJ | CCC | | | JJJ | |
KKK | CCC | | | | KKK |
| DDD | | | | |
HHH | DDD | HHH | | | |
5:现在使用我的原始输入值作为查找所有数据(在列 A 和 B 上)标准化,然后使用索引/匹配函数
6:事后手动清理所有数据
对于较大的数据集,可以轻松地对第 3 步进行宏化,只需遍历该列并粘贴,直到找到下一个值。