我在2个单独的MS Excel 2007工作簿表上有2个表,如下所示:
===========================
no. f_name l_name
===========================
13 Little Timmy
1 John Doe
17 Baby Jessica
---------------------------
===========================
no. f_name l_name
===========================
1 john Tim
16 kyle joe
14 Baby katy
22 qbcd wsde
---------------------------
Run Code Online (Sandbox Code Playgroud)
两者都具有相同的列,但它们可以具有不同的数据.
我想垂直地组合两个表的数据,即单个表与第三个单独的表中的所有数据.如果可能的话,我想添加另一列,其中包含行所在的工作表名称.
===================================
SheetName no. f_name l_name
===================================
Sheet1 13 Little Timmy
Sheet1 1 John Doe
Sheet1 17 Baby Jessica
Sheet2 1 john Tim
Sheet2 16 kyle joe
Sheet2 14 Baby katy
Sheet2 22 qbcd wsde
-----------------------------------
Run Code Online (Sandbox Code Playgroud)
可以不使用宏来完成吗?
小智 9
此答案处理由Excel解释的结构化表格.虽然这些方法可以很容易地转换为原始数据矩阵而没有分配表结构,但是该解决方案的公式和VBA编码将针对真正的结构化表.
第三个表可以使用一些本机工作表公式来维护两个表的组合数据,但是当向依赖表添加或删除行时,保持第三个表的大小正确将需要手动调整大小操作或一些跟踪这些更改并符合的VBA第三个表适合.我已经包含了在这个答案的最后添加源表的工作表名称以及一些表维护VBA代码的选项.
如果您只想要一个没有所有解释的操作示例工作簿,请跳到本答案的末尾,以获取用于创建此过程的工作簿的链接.
我已经使用OP的示例数据来构造两个表(默认情况下)Table1和Table2分别在工作表Sheet1和Sheet2上.我故意从每个工作表的A1单元格中不同程度地抵消它们,以证明结构化表格能够将公式中的自身或另一个结构化表格作为单独的实体进行处理,而不管它在父工作表上的位置如何.第三个表格将以类似的方式构建.这些补偿仅用于演示目的; 他们不是必需的.
构建第三个表的标题,然后选择未来的标题行以及它下面的至少一行,以基于"插入"►"表"►"表格"命令.
Sheet3工作表上新的空第三个表应类似于以下内容.
首先填充第三个表的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)))
Run Code Online (Sandbox Code Playgroud)
该INDEX函数首先检索每个可用行表1.实际的行号是通过引用结构化表的定义部分的ROW函数和一些小数学得出的.当表1用完的行,检索被传递到第二INDEX函数参照表2由IFERROR函数和其顺序的行与所述行和检索ROWS功能使用更多的数学.该COLUMN函数用作COLUMN(A:A)这是会检索参考表的第一列,无论它是在工作表上.当公式填充正确时,这将进入第二,第三等列.
说到填充权,请将公式填入E6.你应该有一些近似以下的东西.
在右下角抓取Table3的大小调整手柄(由下面示例图像中的橙色箭头指示),然后将其向右拖动一列以向表中添加新列.将标头标签重命名为比默认标签更合适的标签.我使用Sheet作为列标签.
虽然您无法直接检索源表的工作表名称,但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))
Run Code Online (Sandbox Code Playgroud)
编译填充表3
如果您不打算使用某个VBA完成这个小项目,以便在从两个源表中的任何一个添加或删除行时维护Table3的维度,那么只需抓住Table3的调整大小句柄并向下拖动,直到您累积了来自两个表的所有数据.有关预期结果的示例图像,请参阅本答案的底部.
如果您计划添加一些VBA,请跳过Table3的完整填充,然后继续下一步.
通过更改工作表数据触发的流程的完全自动化最好由工作表的Worksheet_Change事件宏处理.由于涉及三个表,每个表都在自己的工作表上,因此Workbook_SheetChange事件宏是处理来自多个工作表的更改事件的更好方法.
用Alt+ 打开VBE F11.打开后,查找左上角的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
Run Code Online (Sandbox Code Playgroud)
这两个例程广泛使用Worksheet .CodeName属性.工作表的CodeName是Sheet1,Sheet2,Sheet3等,并且在重命名工作表时不会更改.实际上,即使是更高级的用户也很少改变它们.它们已被使用,因此您无需修改代码即可重命名工作表.但是,他们现在应该指向正确的工作表.如果表和工作表与给定的不同,请修改代码.您可以在上面图像中显示VBE的Project Explorer 的工作表.Name属性旁边的括号中看到单个工作表的代号.
点按Alt+ Q返回工作表.剩下的就是通过选择Table1或Table2中的任何单元格并假装通过点击然后修改它来完成填充Table3.您的结果应类似于以下内容.F2Enter↵
如果您一直跟着到这里,那么您应该有一个非常全面的收集表,它积极地组合来自两个源'子'表的数据.如果您同时添加了VBA,则几乎不存在第三个收集表的维护.
如果您选择重命名三个表中的任何一个或全部,则工作表公式将立即自动反映更改.如果您选择包含Workbook_SheetChange和随附的帮助程序子程序,则必须返回ThisWorkbook代码表并使用"查找和替换"进行适当的更改.
示例工作簿
我已经从我的公共DropBox中提供了完全可操作的示例工作簿.
Table_Collection_w_Sheetname.xlsb
¹ 的细胞功能只能检索保存工作簿的工作表名称.如果尚未保存工作簿,则它没有文件名,并且CELL函数在询问文件名时将返回空字符串.
您可以激活Office 剪贴板(功能区主页选项卡上剪贴板部分右下角的箭头)。复制这两个范围,然后使用“全部粘贴”命令,如下所示。
您仍然需要先在额外的列中填写工作表名称,但这可以通过双击填充柄来完成。

更新
要使用公式获得相同的结果,请尝试填写工作表名称:
=IF(ROW()<=COUNTA(Sheet1!A:A),"Sheet1",IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),"Sheet2",""))
Run Code Online (Sandbox Code Playgroud)
然后向下填写此公式以获取表中的值:
=IF(ROW()<=COUNTA(Sheet1!A:A),Sheet1!A2,IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),INDEX(Sheet2!A:A,ROW()-COUNTA(Sheet1!A:A)+1),""))
Run Code Online (Sandbox Code Playgroud)