此答案涉及 Excel 解释的Structured Tables。虽然这些方法可以很容易地转录为原始数据矩阵而无需分配表结构,但该解决方案的公式和 VBA 编码将针对真正的结构化表。
序言
第三个表可以使用一些本机工作表公式维护两个表的组合数据,但是在从相关表中添加或删除行时保持第三个表的大小正确需要手动调整大小操作或一些跟踪这些数据的 VBA更改并符合第三张表以适应。我在此答案的末尾包含了添加源表的工作表名称以及一些表维护 VBA 代码的选项。
如果您想要的只是一个操作示例工作簿而没有所有解释,请跳到此答案的末尾以获取指向用于创建此过程的工作簿的链接。
示例数据表
我使用 OP 的示例数据在工作表 Sheet1 和 Sheet2 上分别构建了两个名为(默认情况下)Table1 和 Table2 的表。我有意将它们从每个工作表的 A1 单元格中不同程度地偏移,以证明结构化表格能够将公式中的自身或另一个结构化表格作为单独的实体来处理,而不管其在父工作表上的位置如何。第三个表将以类似的方式构建。这些偏移仅用于演示目的;它们不是必需的。
第一步:构建第三张表
为第三个表格构建标题并选择未来的标题行及其下方的至少一行作为插入 ► 表格 ► 表格命令的基础。
Sheet3 工作表上新的第三个空表应类似于以下内容。
第 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 function 首先从 Table1 中检索每个可用行。实际的行号是通过ROW function 引用结构化表的已定义部分以及一些数学运算得出的。当 Table1 的行用完时,检索将传递给 IFERROR function 引用 Table2 的第二个 INDEX 函数,并使用 ROW 和 ROWS functions 使用更多的数学来检索其顺序行。 COLUMN function 用作COLUMN(A:A),它将检索引用表的第一列,而不管它在工作表上的什么位置。当公式正确填写时,这将进入第二列、第三列等。
说到填权,把公式填到E6。你应该有一些近似于以下的东西。
步骤 2.5:[可选] 添加源表的父工作表名称
在右下角抓住 Table3 的大小调整手柄(由下图示例中的橙色箭头指示)并将其向右拖动一列以向表格添加新列。将标题标签重命名为比默认值更合适的名称。我使用 Sheet 作为列标签。
虽然您无法直接检索源表的工作表名称,但 CELL function 可以检索已保存工作簿中任何单元格的完全限定路径、文件名和工作表¹作为其可选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 的全部填充并继续下一步。
第三步:添加一些VBA来维护第三张表
由工作表数据更改触发的流程的完全自动化最好由工作表的Worksheet_Change 事件宏处理。由于涉及三个表,每个表都在自己的工作表中,Workbook_SheetChange event macro 是处理来自多个工作表的更改事件的更好方法。
使用 Alt+F11 打开 VBE。打开后,在左上角寻找 Project Explorer。如果它不可见,则点击 Ctrl+R 将其打开。找到 ThisWorkbook 并右键单击,然后选择查看代码(或直接双击 ThisWorkbook)。
将以下内容粘贴到标题为 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 property。工作表的 CodeName 是 Sheet1、Sheet2、Sheet3 等,并且在重命名工作表时不会更改。事实上,即使是更高级的用户也很少更改它们。它们已被使用,以便您可以重命名工作表而无需修改代码。但是,他们现在应该指向正确的工作表。如果您的表格和工作表与给定的不同,请修改代码。您可以在上图中显示 VBE 的项目资源管理器的工作表 .Name property 旁边的括号中看到各个工作表的代号。
点击 Alt+Q 返回您的工作表。剩下的就是通过选择 Table1 或 Table2 中的任何单元格并假装通过点击 F2 来修改它来完成填充 Table3 然后 Enter↵。您的结果应类似于以下内容。
如果您一直跟随到这里,那么您应该有一个非常全面的集合表,它主动组合了来自两个源“子”表的数据。如果您还添加了 VBA,则几乎不需要维护第三个集合表。
重命名表格
如果您选择重命名三个表中的任何一个或全部,工作表公式将立即自动反映更改。如果您选择包含 Workbook_SheetChange 和随附的帮助程序子过程,则必须返回 ThisWorkbook 代码表并使用 Find & Replace 进行适当的更改。
示例工作簿
我已经从我的公共 DropBox 中提供了完全可操作的示例工作簿。
Table_Collection_w_Sheetname.xlsb
¹ CELL function 只能检索已保存工作簿的工作表名称。如果工作簿尚未保存,则它没有文件名,当要求输入文件名时,CELL 函数将返回一个空字符串。