Combining a table from multiple workbooks into one master workbook - excel

I'm new to VBA and trying to combine a table from multiple workbooks and create one big master workbook.
The basic idea is (what I've done so far):
I've created a blank workbook called "Master" with a sheet name " total" and this is the workbook which I want to paste the extracted data into. I created VBA in this workbook.
I have more than 100 source files from which I want to extract a table. They are all in the same directory: "C:\Users\Documents\Test" The sheets are named "Sheet1".
To create the master workbook, I'd like to locate the last row and start copying new values from the next spreadsheet and my codes are currently not working.
Another issue is each table from different workbooks contain its own header (column names) and I want to skip the headers from the second file.
The tables are located in A1:N53 in each workbook.
Here is my current code:
Private Sub Extraction()
Application.ScreenUpdating = False
Dim wkbDest As Workbook
Dim wkbSource As Workbook
Set wkbDest = ThisWorkbook
Dim LastRow As Long
Dim strExtension As String
Const strPath As String = "C:\Users\Documents\Test\"
strExtension = Dir(strPath & "*.xls*")
Do While strExtension <> ""
Set wkbSource = Workbooks.Open(strExtension)
With wkbSource
LastRow = .Sheets("total").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
.Sheets("Sheet1").Range("A1:N3" & LastRow).Copy wkbDest.Sheets("Master").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
.Close savechanges:=False
End With
strExtension = Dir
Loop
Application.ScreenUpdating = True
End Sub
I definitely messed up where it locates data and copy & paste it to the master workbook.
I'd appreciate it if anyone could help me with modifying my code lines.
Thank you in advance.

Sorry, I wrote this script on the go, so I did not get to test it.
It pretty much follows what you were asking.
Execute script from master file. It uses DIR() to loop over all files inside directory and call for Resize sub procedure in order to obtain and transfer the values from range "A1:N53" into master file.
DIR() will iterate through all files inside filepath. For each file, it will grab the data in sheets(1) range("A1:N53") (change it to range("A2:N53") if you dont want header included. Sorry the explanation was a little ambiguous)
Once the data is obtained through the range, the script will simply resize the range and transfers the value into Sheets(master) based on last row count.
Please let me know if it works, it is doesnt, please follow up on the comments and lets work on it!
Thanks,
Script below:
Option Explicit
Dim fpath As String
Dim fname As String
Dim wb As Workbook
Dim twb As Workbook
Dim rgSrc As Range
Dim rgDest As Range
Sub foo()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wb = ThisWorkbook
fpath = "C:\Users\Documents\Test\"
fname = Dir(fpath)
Do While fname <> ""
Set twb = Workbooks.Open(fpath & fname)
Call Resize
twb.Close
fname = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Private Sub Resize()
' Get all the data in the current region?change it to "A2:N53" is you dont want header included from the files in filepath
Set rgSrc = twb.Sheets(1).Range("A1:N53")
'Get the range destination
Set rgDest = wb.Sheets("Master").Cells(wb.Sheets("Master").Cells(Rows.Count, 1).End(xlUp).Row + 1, 1)
Set rgDest = rgDest.Resize(rgSrc.Rows.Count, rgSrc.Columns.Count)
rgDest.Value2 = rgSrc.Value2
End Sub

You may try the following code that I have been using for some time and appears to be working fine. The promptbox will ask you to select the files and will combine all of them into a stacked database. It will also add a filename so that you can identify the filename from where the data was picked. Code below - Let me know if this helps -
Private Declare PtrSafe Function SetCurrentDirectoryA Lib _
"kernel32" (ByVal lpPathName As String) As Long
Sub ChDirNet(szPath As String)
SetCurrentDirectoryA szPath
End Sub
Sub MergeSpecificWorkbooks()
Dim MyPath As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim SaveDriveDir As String
Dim FName As Variant
Dim FirstCell As String
' Set application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
SaveDriveDir = CurDir
' Change this to the path\folder location of the files.
ChDirNet "C:\Users\nik\test"
FName = Application.GetOpenFilename(FileFilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
If IsArray(FName) Then
' Add a new workbook with one sheet.
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
' Loop through all files in the myFiles array.
For FNum = LBound(FName) To UBound(FName)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(FName(FNum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
With mybook.Worksheets(1)
FirstCell = "A1"
Set sourceRange = .Range(FirstCell & ":" & RDB_Last(3, .Cells))
' Test if the row of the last cell is equal to or greater than the row of the first cell.
If RDB_Last(1, .Cells) < .Range(FirstCell).Row Then
Set sourceRange = Nothing
End If
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If the source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close SaveChanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A.
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = FName(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("B" & rnum)
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close SaveChanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
ChDirNet SaveDriveDir
End Sub
Function RDB_Last(choice As Integer, rng As Range)
' A choice of 1 = last row.
' A choice of 2 = last column.
' A choice of 3 = last cell.
Dim lrw As Long
Dim lcol As Integer
Select Case choice
Case 1:
On Error Resume Next
RDB_Last = rng.Find(What:="*", _
After:=rng.Cells(1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
Case 2:
On Error Resume Next
RDB_Last = rng.Find(What:="*", _
After:=rng.Cells(1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
Case 3:
On Error Resume Next
lrw = rng.Find(What:="*", _
After:=rng.Cells(1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
On Error Resume Next
lcol = rng.Find(What:="*", _
After:=rng.Cells(1), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
On Error Resume Next
RDB_Last = rng.Parent.Cells(lrw, lcol).Address(False, False)
If Err.Number > 0 Then
RDB_Last = rng.Cells(1).Address(False, False)
Err.Clear
End If
On Error GoTo 0
End Select
End Function

Related

Paste Imported CSV to Last Row with VBA - "Subscript out of range"

I was (reluctantly) nice to offer to help my HR department with creating a macro that will import an exported CSV from our accounting software to our existing Excel worksheet to track sales.
I thought I finally figured it out. But, now I'm getting subscript out of range errors when I import the data.
Does anyone see something I'm missing? Thank you.
Note: the staff barely knows how to use a computer, let alone excel. I'm not going to teach them how to use power query. I just wanted to have a nice button "update" they click on... select the file and done.
Dim FileToOpen As String
FileToOpen = GetFileName
If FileToOpen <> "" Then
Dim OpenBook As Workbook
Set OpenBook = Workbooks.Open(FileToOpen)
'Find last cell in CSV file.
Dim Source_LastCell As Range
Set Source_LastCell = LastCell(OpenBook.Worksheets(1))
'Find last cell in reporting workbook.
'ThisWorkbook means the file that the code is in.
Dim Target_LastCell As Range
Set Target_LastCell = LastCell(ThisWorkbook.Worksheets("Services Data")).Offset(1)
'Copy and paste - it's a CSV so won't contain formula, etc.
With OpenBook.Worksheets(1)
.Range(.Cells(2, 1), Source_LastCell).Copy _
Destination:=ThisWorkbook.Worksheets("Services Data").Cells(Target_LastCell.Row, 1)
End With
OpenBook.Close SaveChanges:=False
End If
End Sub
Public Function GetFileName() As String
Dim FD As FileDialog
Set FD = Application.FileDialog(msoFileDialogFilePicker)
With FD
.InitialFileName = ThisWorkbook.Path & Application.PathSeparator
.AllowMultiSelect = False
If .Show = -1 Then
GetFileName = .SelectedItems(1)
End If
End With
Set FD = Nothing
End Function
Public Function LastCell(wrkSht As Worksheet) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With wrkSht
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
End With
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrkSht.Cells(lLastRow, lLastCol)
On Error GoTo 0
End Function
The Subscript out of range on the below line
Set Target_LastCell = LastCell(ThisWorkbook.Worksheets("Services Data")).Offset(1)
indicates that the code was not able to find the worksheet Services Data.
I would do this differently though. Does this help? I have commented the code so you should not have any difficulty to understand it. However, if you do, then simply ask.
Option Explicit
Dim NothingToCopy As Boolean
Sub Sample()
Dim wbCsv As Workbook
Dim wsThis As Worksheet, wsThat As Worksheet
Dim FileToOpen As Variant
Dim rngFromCopy As Range, rngToCopy As Range
'~~> Services Data worksheet
Set wsThis = ThisWorkbook.Sheets("Services Data")
'~~> Browse to csv file
FileToOpen = Application.GetOpenFilename("Csv Files (*.csv), *.csv")
If FileToOpen = False Then Exit Sub
'~~> Open the csv file
Set wbCsv = Workbooks.Open(FileToOpen)
'~~> Set the sheet from where to copy
Set wsThat = wbCsv.Sheets(1)
'~~> Identify the range to copy and paste
Set rngFromCopy = wsThat.Range(wsThat.Cells(2, 1), LastCell(wsThat))
'~~> If CSV is blank then there is nothing to copy
If NothingToCopy = True Then
MsgBox "There is no data to copy"
Else
'~~> Identify where to copy
Set rngToCopy = wsThis.Cells(LastCell(wsThis).Row + 1, 1)
'~~> Copy and paste
rngFromCopy.Copy rngToCopy
'~~> Give time to excel to do the copy and paste
DoEvents
End If
'~~> Close without saving
wbCsv.Close (False)
End Sub
'~~> Function to find last row and column
Private Function LastCell(wrkSht As Worksheet) As Range
Dim wsThatLRow As Long, wsThatLCol As Long
With wrkSht
'~~> Check if the worksheet as has data
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
'~~> Get last row and column
wsThatLRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
wsThatLCol = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
Else
wsThatLRow = 1
wsThatLCol = 1
'~~> CSV has nothing to copy
NothingToCopy = True
End If
Set LastCell = .Cells(wsThatLRow, wsThatLCol)
End With
End Function

How to copy specific range cells from multiple sheets to one sheet?

I have a master workbook in one folder and 100+ child workbooks in a different folder.
Every week I need to copy a specific range of cells from the child workbooks (sheet name is same for all child books) to master workbook (specific sheet).
I tried a few samples but didn't work out.
I fully agree with guys who told you that none will write the code for you, but you are lucky that I have that already written and there may be other people looking for same info, so here it is.
Put the code to module in your master workbook and replace some data as commented:
Option Explicit
Sub GoThroughFilesAndCopyData()
Dim BrowseFolder As String
Dim FileItem As Object
Dim oFolder As Object
Dim FSO As Object
Dim shtWork As Worksheet
Dim lngRow As Long
Dim i As Long: i = 1
Dim strPath As String
Dim MasterSheet As Worksheet
Dim ChildSheet As Worksheet
Application.ScreenUpdating = False
' selecting the folder to look files in
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select the folder with child workbooks"
.Show
On Error Resume Next
Err.Clear
BrowseFolder = .SelectedItems(1)
If Err.Number <> 0 Then
MsgBox "You didn't select anything!"
Application.ScreenUpdating = True
Exit Sub
End If
On Error GoTo 0
End With
Set FSO = CreateObject("Scripting.FileSystemObject") ' creating filesystem object
Set oFolder = FSO.getfolder(BrowseFolder) ' creating folder object
Set MasterSheet = ThisWorkbook.Sheets("masterworksheet_name") 'replace masterworksheet_name with the name of your worksheet in master workbook
For Each FileItem In oFolder.Files 'looking through each file
If UCase(FileItem.Name) Like "*.XLS*" Then 'try open only excel files
i = MasterSheet.Cells(Rows.Count, 1).End(xlUp).row + 1 ' find last not empty row and get a next one which is empty
Workbooks.Open (BrowseFolder & Application.PathSeparator & FileItem.Name)
Set ChildSheet = Workbooks(FileItem.Name).Sheets("worksheet_name") 'worksheet_name - replace with child sheet name
With ChildSheet ' replace your_range_to_copy with the range on a child sheet you want to copy
Range("your_range_to_copy").Copy Destination:=MasterSheet.Cells(i, column_number) 'i - is the number of last empty row, replace column_number - must be the column number of range to insert
.Parent.Close SaveChanges:=False 'close child workbook without saving
End With
End If
Next
Application.ScreenUpdating = True
End Sub
This will do what you want.
Copy a range of each sheet
Note: This example use the function LastRow
This example copy the range A1:G1 from each worksheet.
Change the range in this code line
'Fill in the range that you want to copy
'Set CopyRng = sh.Range("A1:G1")
Sub CopyRangeFromMultiWorksheets()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh
Last = LastRow(DestSh)
'Fill in the range that you want to copy
Set CopyRng = sh.Range("A1:G1")
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look at the example below this macro
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
'Optional: This will copy the sheet name in the H column
DestSh.Cells(Last + 1, "H").Resize(CopyRng.Rows.Count).Value = sh.Name
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Also . . .
'Common Functions required for all routines
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = 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
Function LastCol(sh As Worksheet)
On Error Resume Next
LastCol = 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

Merging excel sheets from books in the directory into one: dynamic source data

So im trying to merge multiple .csv files into one excel workbook.
All .csv have 1 sheet and a random amount of row, but fixed amount of columns.
I can assing fixed range, but that will overburdain the file, how do I define a range, which will select all filled rows in the file and paste them in the new one?
Sub Merge()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, Fnum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
'Fill in the path\folder where the files are
MyPath = ActiveWorkbook.Path & "\"
'If there are no Excel files in the folder exit the sub
FilesInPath = Dir(MyPath & "*.csv")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
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
'Change ScreenUpdating, Calculation and EnableEvents
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
'Add a new workbook with one sheet
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
'Loop through all files in the array(myFiles)
If Fnum > 0 Then
For Fnum = LBound(MyFiles) To UBound(MyFiles)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(MyPath & MyFiles(Fnum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
With mybook.Worksheets(1)
Set sourceRange = .Range("A1:C1")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
'if SourceRange use all columns then skip this file
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "Sorry there are not enough rows in the sheet"
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
'Copy the file name in column A
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(Fnum)
End With
'Set the destrange
Set destrange = BaseWks.Range("B" & rnum)
'we copy the values from the sourceRange to the destrange
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next Fnum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Exactly in here the range is the source range defined, i need to swap it to dynamic source range
With mybook.Worksheets(1)
Set sourceRange = .Range("A1:C1")
End With
If I understand you correctly, you would like to have a dynamic way to select all the cells that have values in the sheet and copy to another "master workbook". This is how I've done this in the past.
Sub SelectActualUsedRange()
Dim FirstCell As Range, LastCell As Range
Set LastCell = Cells(Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row, _
Cells.Find(What:="*", SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Column)
Set FirstCell = Cells(Cells.Find(What:="*", After:=LastCell, SearchOrder:=xlRows, _
SearchDirection:=xlNext, LookIn:=xlValues).Row, _
Cells.Find(What:="*", After:=LastCell, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, LookIn:=xlValues).Column)
Range(FirstCell, LastCell).Select
End Sub
Instead of hard coding a range in the code you can use this small function to get the actual used range.
Hope this answers your question.
Either one of these two options should work for you.
' Merge data from multiple sheets into separate sheets
Sub AnalysisMerger1()
Dim WSA As Worksheet
Dim bookList As Workbook
Dim SelectedFiles As Variant
Dim NFile As Long
Dim FileName As String
Dim Ws As Worksheet, vDB As Variant, rngT As Range
Dim vFn, myFn As String
Application.ScreenUpdating = False
SelectedFiles = Application.GetOpenFilename(filefilter:="Excel Files (*.csv*), *.csv*", MultiSelect:=True)
If IsEmpty(SelectedFiles) Then Exit Sub
For NFile = LBound(SelectedFiles) To UBound(SelectedFiles)
FileName = SelectedFiles(NFile)
vFn = Split(FileName, "\")
myFn = vFn(UBound(vFn))
myFn = Replace(myFn, ".csv", "")
Set bookList = Workbooks.Open(FileName, Format:=2)
Set WSA = bookList.Sheets(1)
vDB = WSA.UsedRange
bookList.Close (0)
Set Ws = Sheets.Add(after:=Sheets(Sheets.Count))
ActiveSheet.Name = myFn
Ws.Range("a1").Resize(UBound(vDB, 1), UBound(vDB, 2)) = vDB
Next
Application.ScreenUpdating = True
End Sub
' Merge data from multime files into one sheet.
Sub AnalysisMerger2()
Dim WSA As Worksheet
Dim bookList As Workbook
Dim SelectedFiles() As Variant
Dim NFile As Long
Dim FileName As String
Dim Ws As Worksheet, vDB As Variant, rngT As Range
Application.ScreenUpdating = False
Set Ws = ThisWorkbook.Sheets(1)
Ws.UsedRange.Clear
'change folder path of excel files here
SelectedFiles = Application.GetOpenFilename(filefilter:="Excel Files (*.csv*), *.csv*", MultiSelect:=True)
For NFile = LBound(SelectedFiles) To UBound(SelectedFiles)
FileName = SelectedFiles(NFile)
Set bookList = Workbooks.Open(FileName, Format:=2)
Set WSA = bookList.Sheets(1)
With WSA
vDB = .UsedRange
Set rngT = Ws.Range("a" & Rows.Count).End(xlUp)(2)
If rngT.Row = 2 Then Set rngT = Ws.Range("a1")
rngT.Resize(UBound(vDB, 1), UBound(vDB, 2)) = vDB
bookList.Close (0)
End With
Next
Application.ScreenUpdating = True
Ws.Range("A1").Select
End Sub

Excel VB macro copy data

This macro serves the purpose to copy data from multiple excel sheets from a designated source range and then copies it to a master sheet.
I'm very limited when it comes to VB knowledge. If possible can we augment the macro to skip copying any rows that have blank cells, like a filter? Below the source range is set to B5:N6. Based on our excel sheets column B can be used as a means to apply this filter, i.e. if any cell in column B is empty, then skip that entire row in the copy process. The output would then need to be condensed and not include any spaces between the copied entries as a result of the skipped rows.
If VBA7 Then
Declare PtrSafe Function SetCurrentDirectoryA Lib _
"kernel32" (ByVal lpPathName As String) As Long
Else
Declare Function SetCurrentDirectoryA Lib _
"kernel32" (ByVal lpPathName As String) As Long
End If
Sub ChDirNet(szPath As String)
SetCurrentDirectoryA szPath
End Sub
Sub Basic_Example_2()
Dim MyPath As String
Dim SourceRcount As Long, Fnum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim SaveDriveDir As String
Dim FName As Variant
'Change ScreenUpdating, Calculation and EnableEvents
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
SaveDriveDir = CurDir
ChDirNet "C:\Test\"
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
If IsArray(FName) Then
'Add a new workbook with one sheet
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
'Loop through all files in the array(myFiles)
For Fnum = LBound(FName) To UBound(FName)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(FName(Fnum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
With mybook.Worksheets(1)
Set sourceRange = .Range("B5:N6")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
'if SourceRange use all columns then skip this file
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "Sorry there are not enough rows in the sheet"
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
'Set the destrange
Set destrange = BaseWks.Range("A" & rnum)
'we copy the values from the sourceRange to the destrange
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next Fnum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
ChDirNet SaveDriveDir
End Sub

Excel Macro [Visual Basic] Merge only a few cells of every 1st worksheet, of multiple workbooks in a folder

I use the following visual basic to select multiple excel workbooks in a folder, and merge them into the second worksheet of my active workbook.
In the actual code example it merges the complete range "as is", including all columns, rows and blanco cells. I only need to use the copied data of a few cells (B3, B5, B7 & E48) from first sheet in the selected workbooks, and paste them in only one row per merged workbook on the second sheet.
How can I prevent the macro from writing all these unnecessary data in the destination sheet? Or, at least, how can I combine a range of B3:E48 into one row in the destination sheet?
Private Declare Function SetCurrentDirectoryA Lib _
"kernel32" (ByVal lpPathName As String) As Long
Sub ChDirNet(szPath As String)
SetCurrentDirectoryA szPath
End Sub
Sub MergeSpecificWorkbooks()
Dim MyPath As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim SaveDriveDir As String
Dim FName As Variant
' Set application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
SaveDriveDir = CurDir
' Change this to the path\folder location of the files.
ChDirNet "H:\xlstest"
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
If IsArray(FName) Then
' Add a new workbook with one sheet.
'Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
'prevent prompting new workbook, write data in active sheet number two
Set BaseWks = ActiveWorkbook.Worksheets(2)
rnum = 1
' Loop through all files in the myFiles array.
For FNum = LBound(FName) To UBound(FName)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(FName(FNum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
With mybook.Worksheets(1)
Set sourceRange = .Range("B5:E48")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If the source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A.
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = FName(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("B" & rnum)
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
ChDirNet SaveDriveDir
End Sub
This code is based on Ron de Bruin's merging examples, actually none of all other relevant internet sources provide a solution.
This will give you some idea of how to create a non-contiguous range, and how to loop through and copy its values to a single row.
Sub Tester()
Dim a As Range, c As Range
Dim rngSrc As Range, rngDest As Range
Dim x As Long
Set rngSrc = ActiveSheet.Range("B3,B5,B7,E48")
Set rngDest = ActiveSheet.Range("A1")
x = 0
For Each a In rngSrc.Areas
For Each c In a.Cells
x = x + 1
rngDest.Offset(0, x - 1).Value = c.Value
Next c
Next a
End Sub

Resources