Excel VBA - 将多个文件中的特定列合并到一张工作表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25219350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Excel VBA - Merge specific columns from multiple files to one sheet
提问by John Young
I have hundreds of excel files that I want to combine into one file. The problem is that these files contain hundreds of columns of extra data that I do not need. Further complicating things is that the column positions differ between workbooks and workbooks have differing number of columns. I want to create a macro that will go through and open each file, search for the columns I need, and then copy those columns of data and combine them into one master file.
我有数百个要合并到一个文件中的 Excel 文件。问题是这些文件包含数百列我不需要的额外数据。更复杂的是,工作簿之间的列位置不同,工作簿的列数也不同。我想创建一个宏,它将遍历并打开每个文件,搜索我需要的列,然后复制这些数据列并将它们合并到一个主文件中。
The way the below code works is as follows: place all the files you want to combine into one folder Type the headers you want to search for and combine within those files on a new workbook.
以下代码的工作方式如下: 将所有要合并的文件放在一个文件夹中 键入要搜索的标题并在新工作簿上的这些文件中进行合并。
If you have 4 columns in your files named: Name Date Product and Time
如果您的文件中有 4 列名为:名称日期产品和时间
Then typing Date and Time in A1 and B1 in a new worksheet will search all the files and combine any columns found with matching headers to a compilation sheet.
然后在新工作表中的 A1 和 B1 中键入日期和时间将搜索所有文件,并将找到的任何具有匹配标题的列合并到一个编辑表中。
Thanks to Ron DeBruin for most of the filesystem selection.
感谢 Ron DeBruin 为大多数文件系统选择。
'Option Explicit
'takes worksheet and returns last row
Private Function LastRowUsed(sh As Worksheet) As Long
On Error Resume Next
LastRowUsed = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
'takes worksheet and returns last column
Private Function LastColUsed(sh As Worksheet) As Long
On Error Resume Next
LastColUsed = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
Function GetFileListArray() As String()
Dim fileDialogBox As FileDialog
Dim SelectedFolder As Variant
Dim MYPATH As String
Dim MYFILES() As String
Dim FILESINPATH
Dim FNUM, i As Integer
'''''
Set fileDialogBox = Application.FileDialog(msoFileDialogFolderPicker)
'Use a With...End With block to reference the FileDialog object.
With fileDialogBox
If .Show = -1 Then 'the user chose a folder
For Each SelectedFolder In .SelectedItems
MYPATH = SelectedFolder 'asign mypath to the selected folder name
' MsgBox "The path is: " & SelectedFolder 'display folder selected
Next SelectedFolder
'The user pressed Cancel.
Else
MsgBox "Cancel was pressed or Invalid folder chosen, ending macro"
Exit Function
End If
End With
'Set the file dialog object variable to Nothing to clear memory
Set fileDialogBox = Nothing
If Right(MYPATH, 1) <> "\" Then
MYPATH = MYPATH & "\"
End If
FILESINPATH = Dir(MYPATH & "*.csV")
If FILESINPATH = "" Then
MsgBox "No files found"
Exit Function
End If
'Fill the array(myFiles)with the list of Excel files in the folder
FNUM = 0
Do While FILESINPATH <> ""
FNUM = FNUM + 1
ReDim Preserve MYFILES(1 To FNUM)
MYFILES(FNUM) = FILESINPATH
FILESINPATH = Dir()
Loop
GetFileListArray = MYFILES()
End Function
Sub RFSSearchThenCombine()
'search first worksheet in files opened, change to search other worksheets
Const SHEET_TO_SEARCH = 1
Dim FileList() As String
Dim CurrentFolder As String
Dim openedWorkBook As Workbook, HeadingWorkbook As Workbook
Dim OpenedWorkSheet As Worksheet, HeadingWorkSheet As Worksheet
Dim i, counter, x As Integer
Dim LRowHeading, LRowOpenedBook, LColHeading, LColOpenedBook As Long
Dim dict As dictionary
Dim searchValue
'set original workbook with headings to retrieve
Set HeadingWorkbook = ActiveWorkbook
Set HeadingWorkSheet = HeadingWorkbook.Sheets(1)
'find last column on heading worksheet
LColHeading = LastColUsed(HeadingWorkSheet)
'create dictionary to link headers to position in heading worksheet
Set dict = CreateObject("Scripting.Dictionary")
For x = 1 To LColHeading
dict.Add HeadingWorkSheet.Cells(1, x).Value, x
Next x
FileList() = GetFileListArray()
For counter = 1 To UBound(FileList)
Set openedWorkBook = Workbooks.Open(CurrentFolder & FileList(counter))
Set OpenedWorkSheet = openedWorkBook.Sheets(SHEET_TO_SEARCH)
LColOpenedBook = LastColUsed(openedWorkBook.Sheets(1))
LRowOpenedBook = LastRowUsed(openedWorkBook.Sheets(1))
LRowHeading = LastRowUsed(HeadingWorkSheet)
For i = 1 To LColOpenedBook 'search headers from a1 to last header
searchValue = OpenedWorkSheet.Cells(1, i).Value 'set search value to current header
If dict.Exists(searchValue) Then
OpenedWorkSheet.Range(OpenedWorkSheet.Cells(1, i), _
OpenedWorkSheet.Cells(LRowOpenedBook, i)).Copy _
(HeadingWorkSheet.Cells(LRowHeading, dict.Item(searchValue)))
End If
Next
openedWorkBook.Close (False)
Next ' move on to next file
End Sub
采纳答案by Bernard Saucier
Here's how you'd use a dictionary to store the name and column number of the columns of interest (based on an arbitrarily named "COMPILATION SHEET"). Remember you need to enable the reference to "Microsoft Scripting Runtime".
下面是如何使用字典来存储感兴趣的列的名称和列号(基于任意命名的“COMPILATION SHEET”)。请记住,您需要启用对“Microsoft Scripting Runtime”的引用。
Sub InitiateDictionary()
Dim d As Dictionary
Set d = CreateObject("Scripting.Dictionary")
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("COMPILATION SHEET")
lastCol = LastColUsed(ws)
For x = 1 To lastCol
d.Add ws.Cells(1, x), x
Next x
End Sub
Private Function LastColUsed(sh As Worksheet)
On Error Resume Next
LastColUsed = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
All you need to do is elaborate a way to know if an element is contained by the dictionary (define the function DContains(dictionary, string)
). There are examples on Google on how to do that. Once you know that the header is inside the dictionary, you can use that header name to know the column number it refers to. A bit like this :
您需要做的就是详细说明一种方法来了解某个元素是否包含在字典中(定义函数DContains(dictionary, string)
)。谷歌上有关于如何做到这一点的例子。一旦您知道标题在字典中,您就可以使用该标题名称来了解它所指的列号。有点像这样:
colNumber = 0
headerToFind = "Header_A"
found = DContains(d, headerToFind)
if found then
colNumber = d(headerToFind)
end if
if colNumber > 0 then
'Perform copy to column "colNumber" !
end if
To determine how many entries are in the dictionary, simply use the .Count
property.
要确定字典中有多少条目,只需使用该.Count
属性。
And yes, in this case Cells(x,1)
is the same as Cells(x,1).value
.
是的,在这种情况下Cells(x,1)
与Cells(x,1).value
.