This answer deals with
Structured Tables as interpreted by Excel. While the methods could easily be transcribed to raw data matrixes without assigned table structure, the formulas and VBA coding for this solution will be targeted at true structured tables.
Preamble
A third table can maintain the combined data of two tables with some native worksheet formulas but keeping the third table sized correctly as rows are added or deleted to/from the dependent tables will require either manual resizing operations or some VBA that tracks these changes and conforms the third table to suit. I've included options to add both the source table's worksheet name as well as some table maintenance VBA code at the end of this answer.
If all you want is an operational example workbook without all the explanation, skip to the end of this answer for a link to the workbook used to create this procedure.
Sample data tables
![Table Collection Sample Data](https://istack.dev59.com/gSwPI.webp)
我使用了原帖中的样例数据,在工作表Sheet1和Sheet2上分别构建了两个名为默认名称为Table1和Table2的表格。为了演示结构化表格能够像独立实体一样在公式中引用自身或其他结构化表格,而不受其在父级工作表上位置的影响,我故意让它们从各自工作表的A1单元格偏移了不同程度。第三个表也将以类似的方式构建。这些偏移仅供演示;并非必需。
步骤1:构建第三个表
构建第三个表的表头,并选择该未来的表头行以及至少一行以下内容,以便基于插入►表格►表格命令进行操作。
![Combining Tables New Table](https://istack.dev59.com/MiP52.webp)
你的Sheet3工作表上的新空第三个表格应该如下所示。
![Collecting Table Data Build New Table](https://istack.dev59.com/8r9aJ.webp)
步骤2:填充第三个表格
从填充第三个表格的DataBodyRange的第一个单元格开始。在本例中,这将是Sheet3!C6。键入或粘贴以下公式到C6中,记住它基于默认表名。如果您已更改表名,请相应地进行调整。
=IFERROR(INDEX(Table1, ROW([@[no.]])-ROW(Table3[#Headers]),COLUMN(A:A)), INDEX(Table2, ROW([@[no.]])-ROW(Table3[#Headers])-ROWS(Table1),COLUMN(A:A)))
INDEX函数首先从Table1中检索每一行可用数据。实际行数是通过ROW函数引用结构化表格的定义部分并进行简单计算得出的。当Table1没有更多行时,检索将通过IFERROR函数传递到引用Table2的第二个INDEX函数,并使用ROW和ROWS函数以及更多的数学方法来检索其连续的行。COLUMN函数用作COLUMN(A:A)
,它将检索引用表格的第一列,无论它在工作表上的位置如何。随着公式向右填充,这将进展到第二列、第三列等。
说到正确填充,将公式正确地填充到E6。你应该会得到以下近似结果。
![Aggregating table data, third table](https://istack.dev59.com/5DPox.webp)
步骤2.5:[可选] 添加源表的父工作表名称
在下图所示的样本图像中,抓取Table3的大小调整手柄(由橙色箭头指示),向右拖动一个列以添加新列到表中。将标题标签重命名为比默认值更合适的内容。我使用了Sheet作为列标签。
![Collating table data - source worksheet name](https://istack.dev59.com/hniyk.webp)
虽然您无法直接检索源表的工作表名称,但
CELL函数可以检索保存的工作簿¹中任何单元格的完全限定路径、文件名和工作表作为其可选
info_types之一。
将以下公式放入Table3的新列的第一行空单元格中。
=TRIM(RIGHT(SUBSTITUTE(CELL("filename", IF((ROW([@[no.]])-ROW(Table3[#Headers]))>ROWS(Table1), Table2, Table1)), CHAR(93), REPT(CHAR(32), 999)), 255))
完成Table3的填充
如果您不打算使用一些VBA来维护Table3的尺寸,以便在两个源表中添加或删除行时,只需抓取Table3的调整大小手柄并向下拖动,直到累积了来自两个表的所有数据。请参阅本答案底部的示例图像以查看预期结果。
如果您计划添加一些VBA,则跳过对Table3的完全填充,并继续进行下一步。
步骤3:添加一些VBA以维护第三个表格
通过工作表的Worksheet_Change事件宏启动由工作表数据更改触发的完全自动化进程是最好的方法。由于涉及三个表格,每个表格都在其自己的工作表上,因此Workbook_SheetChange事件宏是处理来自多个工作表的更改事件的更好方法。
使用
Alt+
F11 打开 VBE。打开后,在左上角寻找
项目资源管理器 。如果看不见,请按
Ctrl+
R 打开。找到
ThisWorkbook ,右键点击然后选择查看代码(或者双击 ThisWorkbook)。
![Collect data from multiple tables](https://istack.dev59.com/Bfosi.webp)
将下面的内容粘贴到类似于
Book1 - ThisWorkbook (Code) 的新窗格中。
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Select Case Sh.Name
Case Sheet1.Name
If Not Intersect(Target, Sheet1.ListObjects("Table1").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
Case Sheet2.Name
If Not Intersect(Target, Sheet2.ListObjects("Table2").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
End Select
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Private Sub update_Table3()
Dim iTBL3rws As Long, rng As Range, rngOLDBDY As Range
iTBL3rws = Sheet1.ListObjects("Table1").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet2.ListObjects("Table2").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet3.ListObjects("Table3").DataBodyRange.Cells(1, 1).Row - _
Sheet3.ListObjects("Table3").Range.Cells(1, 1).Row
With Sheet3.ListObjects("Table3")
Set rngOLDBDY = .DataBodyRange
.Resize .Range.Cells(1, 1).Resize(iTBL3rws, .DataBodyRange.Columns.Count)
If rngOLDBDY.Rows.Count > .DataBodyRange.Rows.Count Then
For Each rng In rngOLDBDY
If Intersect(rng, .DataBodyRange) Is Nothing Then
rng.Clear
End If
Next rng
End If
End With
End Sub
这两个例程广泛使用工作表的
.CodeName属性。工作表的
CodeName 是
Sheet1、Sheet2、Sheet3等,并且在工作表重命名时不会更改。实际上,即使是高级用户也很少更改它们。它们被用来使您能够重命名工作表而无需修改代码。但是,它们现在应该指向正确的工作表。如果您的表格和工作表与给定的不同,请修改代码。您可以在上面显示 VBE 的项目资源管理器中的工作表
.Name属性 旁边的括号中看到各个工作表的代码名称。
点击 Alt+Q 返回到您的工作表。接下来要做的就是通过选择 Table1 或 Table2 中的任意单元格,并模拟修改它们,然后按下 F2 键再按下 Enter↵ 键来完成填充 Table3。您的结果应该如下所示。
![Combine two tables into one automatically](https://istack.dev59.com/r9GQ6.webp)
如果你一路跟随到这里,那么你应该拥有一个相当全面的集合表,它可以积极地将来自两个源“子”表的数据结合起来。如果你也添加了VBA,那么第三个集合表的维护几乎是不存在的。
重命名表格
如果你选择重命名任何或所有三个表格,则工作表公式将立即自动反映更改。如果你选择包含Workbook_SheetChange和相应的帮助程序子过程,你需要回到ThisWorkbook代码表并使用查找和替换来进行适当的更改。
示例工作簿
我已经从我的公共DropBox中提供了完全操作的示例工作簿。
Table_Collection_w_Sheetname.xlsb
¹ CELL函数只能检索已保存工作簿的工作表名称。如果工作簿尚未保存,则没有文件名,当要求文件名时,CELL函数将返回空字符串。