Delete blank rows from Excel table - vba

I have code the merges multiple excel workbooks together, and updates the data into another workbook "Master", however, when it paste the data into the master it leaves numerous blank rows prior to the insert of the data table.
I have tried various posted solutions, however, when I incorporate the new code it is failing. I could use some assistances in modifying my code to handle the removal of the inserted blank rows in my table, prior to the data being updated.
See '>>>>>>>>> marked in the code.
Public Function MergeMultipleSheets()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, FNum As Long
Dim myBook As Workbook, wbMaster As Workbook
Dim BaseWks As Worksheet, ws As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim rng As Range, SearchValue As String
Dim FilterField As Integer, RangeAddress As String
Dim ShName As Variant, ShNames As Variant, RwCount As Long, nName As Variant
Dim nFilter As String
Dim currentrow As Long
Dim LastRow As Long
MyPath = ThisWorkbook.Sheets("Data Input").Range("B1")
' ShNames = Array("ProjSum", "FinSum", "CommSum", "InvPlan", "ResPlan_Data")
ShNames = Array("ProjSum", "ResPlan_Data")
Set wbMaster = ActiveWorkbook
'**********************************************************
'Merge data into existing worksheets in this workbook
'**********************************************************
' Add a slash after MyPath if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
'FilesInPath = Dir(MyPath & "week*.xl*")
nFilter = ThisWorkbook.Sheets("Data Input").Range("B2")
If nFilter = "" Or FilesInPath = "" Then
FilesInPath = Dir(MyPath & "*.xl*")
End If
' Fill the myFiles array 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 application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
' Clear data from summary worksheets
For Each ShName In ShNames
Set rng = Nothing
On Error Resume Next
Set rng = wbMaster.Worksheets(ShName).UsedRange
On Error GoTo 0
If Not rng Is Nothing Then
'Don't delete header labels in the first row
Set rng = rng.Offset(1, 0)
End If
Next
rnum = 1
' Loop through all files in the myFiles array.
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), UpdateLinks:=0)
'**************************************************************************************************
'Removes unused Named Ranges from Name Manager from the Various JC files to prevent error dialogs.
'**************************************************************************************************
For Each nName In Names
If InStr(1, nName.RefersTo, "#REF!") > 0 Then
nName.Delete
End If
If InStr(1, nName.RefersTo, "https://") > 0 Then
nName.Delete
End If
Next nName
On Error GoTo 0
If Not myBook Is Nothing Then
For Each ShName In ShNames
Set ws = Nothing
On Error Resume Next
Set ws = myBook.Worksheets(ShName)
On Error GoTo 0
'****************************************************************************************************************************
'Calls function to update ResPlan in active workbook
'Executes Updating of the ResPlan data to proper format for extraction of data in correct format
'****************************************************************************************************************************
If ShName = "ResPlan_Data" Then
Call UnpivotResPlan
myBook.Save
End If
'**************************************************
'Updates template data per shName
'*************************************************
'>>>>>>>>>
If Not ws Is Nothing Then
Set BaseWks = wbMaster.Worksheets(ShName)
Set sourceRange = ws.UsedRange
'Exclude header labels
Set rng = sourceRange.Offset(1, 0).Resize(sourceRange.Rows.Count - 1, sourceRange.Columns.Count)
rng.ClearContents
Dim rngBlanks As Excel.Range
With wbMaster.Worksheets(ShName).ListObjects("Res_Plan_Data")
On Error Resume Next
Set rngBlanks = Intersect(.DataBodyRange, .ListColumns("New").Range).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rngBlanks Is Nothing Then
rngBlanks.Delete
End If
End With
RwCount = rng.Rows.Count
rnum = BaseWks.Cells(BaseWks.Rows.Count, 1).End(xlUp).Row + 1
BaseWks.Cells(rnum, "A").Resize(RwCount).Value _
= myBook.Name
BaseWks.Cells(rnum, "B").Resize(RwCount, rng.Columns.Count).Value = rng.Value
End If
Next
' Close the workbook without saving.
myBook.Close savechanges:=True
End If
' Open the next workbook.
Next FNum
' Set the column width in the new workbook.
BaseWks.Columns.AutoFit
'Prepares Salary Detail for Updating.
Call UnpivotSalaryDetail
End If
Call Reset
' ActiveWorkbook.Model.Refresh
If Worksheets("Resplan_Data").Visible = True Then
Worksheets("Resplan_Data").Visible = False
End If
MsgBox "Update completed!"
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Function
Sub ClearBlankCellsInColumnNew()
Dim rngBlanks As Excel.Range
With Worksheets("ResPlan_Data").ListObjects("Res_Plan_Data")
On Error Resume Next
Set rngBlanks = Intersect(.DataBodyRange, .ListColumns("New").Range).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rngBlanks Is Nothing Then
rngBlanks.Delete
End If
End With
End Sub

Not sure if this is what you are after but it will delete all the rows which have a blank cell in column A
Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
A quick explination Columns("A:A") is the target column, change the letter and add numbers or varibles as you wish. .SpecialCells(xlCellTypeBlanks) is what cell it will target, in this case it will be the blank cells (record a macro and press Ctrl + G for any variations you need). And lastly .EntireRow.Delete will delete the target row(s).
So it will look in column A, and if there is any blank cells in column A it will delete that row.
Hope this helps, leave a comment if you need anything clarifed

Related

I am trying to have this macro include the ability to copy data from multiple worksheets in a workbook but it will only copy from the first worksheet [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
This is my data below.
The code works just doesn't fit my requirements. I need to add the functionality that will allow me to pull data from multiple worksheets in 1 workbook but currently it will only pull the data from 1 worksheet in 1 workbook.
I've included the code to go through different worksheets but as of now the code will only extract data from 1 worksheet in 1 workbook.
Any help is greatly appreciated. Thanks!
Sub MergeAllWorkbooks()
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
' Change this to the path\folder location of your files.
MyPath = "C:\Users\mp180423\Desktop\Gas"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
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 myFiles array.
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
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
Debug.Print ws.Name
Next
If Not mybook Is Nothing Then
On Error Resume Next
' Change this range to fit your own needs.
With mybook.Worksheets(3)
Set sourceRange = .Range("A15:B20")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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.
For Each ws In Worksheets
ws.Activate
Debug.Print ws.Name
Next
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(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
Range("B1").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$C$66").AutoFilter Field:=2, Criteria1:= _
"Kilowatt hours used Current period"
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
MsgBox ("Merge Completed.")
End Sub
I expect that the single worksheet from the single workbook which this code was correctly working for, would be the only workbook with at least 3 worksheets.
When selecting the range you have:
With mybook.Worksheets(3)
Set sourceRange = .Range("A15:B20")
End With
Note that this restricts the data to the range from only the 3rd (third) worksheet from every workbook.
Also note that on the line prior, you have:
On Error Resume Next
This would effectively mask the errors coming from attempting to extract data from all the non-existing 3rd worksheets. For the workbook with at least 3 worksheets, since the With mybook.Worksheets(3) is hard-coded into your code, this was the only worksheet the data was pulled from.
(And the reason it wasn't duplicated for each worksheet in that workbook, is because the cycles through the worksheets were restricted to the Debug.Print lines. The code for the data-moving only cycled through once for each workbook)
Below, you will see three (3) sections:
Change Details.
This is to help high-light the changes I made to your code so that it cycles through the data-moving for each worksheet, pulling once from each worksheet.
Corrected
This is for ease of copy/pasting the code
Original
This is to maintain a copy of the original code I based my answer off of (in case of changes).
Change Details
From original:
Set mybook = Workbooks.Open(MyPath & MyFiles(FNum))
On Error GoTo 0
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
Debug.Print ws.Name
Next
If Not mybook Is Nothing Then
On Error Resume Next
' Change this range to fit your own needs.
With mybook.Worksheets(3)
Set sourceRange = .Range("A15:B20")
End With
Changed to:
Set mybook = Workbooks.Open(MyPath & MyFiles(FNum))
On Error GoTo 0
Dim ws As Worksheet
If Not mybook Is Nothing Then
For Each ws In Worksheets
On Error Resume Next
' Change this range to fit your own needs.
With ws
Set sourceRange = .Range("A15:B20")
End With
Top-half:
Although I kept the Dim ws As Worksheet, I removed the Debug.Print cycle through all worksheets, as it had no effect on any other code.
Lower-half:
Added a For Each ws In Worksheets around the functional code (which required adding Next ws above mybook.Close savechanges:=False), and shifted the with statement from With mybook.Worksheets(3) to With ws
Since there was another extraneous Debug.Print cycle right before the file name was added to column A, I replaced it with Debug.Print ws.Name & ": #" & FNum to be a bit more informative.
Corrected
Sub MergeAllWorkbooks()
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
' Change this to the path\folder location of your files.
MyPath = "C:\Users\mp180423\Desktop\Gas"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
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 myFiles array.
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
' Added cycle through worksheets
Dim ws As Worksheet
If Not mybook Is Nothing Then
For Each ws In Worksheets
On Error Resume Next
' Change this range to fit your own needs.
' Shifted reference to current worksheet-of-interest
With ws
Set sourceRange = .Range("A15:B20")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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
' Prints file name and index number in immediate window.
Debug.Print ws.Name & ": #" & FNum
' Copy the file name in column A.
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(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
'Cycles through next worksheet-of-interest
Next ws
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
Range("B1").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$C$66").AutoFilter Field:=2, Criteria1:= _
"Kilowatt hours used Current period"
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
MsgBox ("Merge Completed.")
End Sub
Original
Sub MergeAllWorkbooks()
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
' Change this to the path\folder location of your files.
MyPath = "C:\Users\mp180423\Desktop\Gas"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
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 myFiles array.
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
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
Debug.Print ws.Name
Next
If Not mybook Is Nothing Then
On Error Resume Next
' Change this range to fit your own needs.
With mybook.Worksheets(3)
Set sourceRange = .Range("A15:B20")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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.
For Each ws In Worksheets
ws.Activate
Debug.Print ws.Name
Next
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(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
Range("B1").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$C$66").AutoFilter Field:=2, Criteria1:= _
"Kilowatt hours used Current period"
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
MsgBox ("Merge Completed.")
End Sub

Sub procedure for importing the sheets it's substandar

I get this code to work for a time but the last couple of days it has not been working. from active workbook1 its suppose to import the sheets to Thisworkbook2:
Sub ImportallWBsh()
'https://michaelaustinfu.files.wordpress.com/2013/03/excel-vba-for-dummies-3rd-edition.pdf, Page 245
Dim Finfo As String
Dim FilterIndex As Integer
Dim Title As String
Dim Filename As Variant
Dim wb As Workbook
'Setup the list of file filters
Finfo = "Excel Files (*.xlsx),*xlsx,"
'Display *.* by default
FilterIndex = 1
'Set the dialog box caption
Title = "Select a File to Import"
'Get the Filename
Filename = Application.GetOpenFilename(Finfo, _
FilterIndex, Title)
'Handle return info from dialog box
If Filename = False Then
MsgBox "No file was selected."
Else
MsgBox "You selected " & Filename
End If
On Error Resume Next
Set wb = Workbooks.Open(Filename)
FilenameWorkbook.Sheets.Copy _
After:=ThisWorkbook.Sheets("Sheet3")
wb.Close True
ThisWorkbook.Sheets("Sheet1").Select
End Sub
Do you know what might be wrong about it.
Thank you
You've got a couple issues going on...
You are using Set incorrectly. GetOpenFileName returns a string. Workbooks.Open returns an object. Check this out. The first section of your could read:
s = Application.GetOpenFilename()
Set Wb1 = Workbooks.Open (s)
You're also opening workbook s twice, plus you create object objexcel which creates a new instance of Excel, but you don't close it with Set objexcel = Nothing, so each time you run the code, you'll have another copy of Excel open in the background.
(Close Excel, then CTRL+ALT+DEL to check your Task Manager and I bet you'll see what I mean!)
To start with I suggest you try this search, which will show a number of solutions to the same question that have worked for others, such as this and this.
Something like this should do the job for you.
Sub Basic_Example_1()
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 = "C:\Users\Ron\test"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'If there are no Excel files in the folder exit the sub
FilesInPath = Dir(MyPath & "*.xl*")
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
https://www.rondebruin.nl/win/s3/win008.htm
The correct line code needs to be:
ActiveWorkbook.Sheets.Copy _
After:=ThisWorkbook.Sheets("Hoja3")
So the code work properly. Thank you

Create separate row for each item when merging multiple workbooks

I have several hundred spreadsheets that I would like to combine into a single master sheet. Each spreadsheet contains general description information in several sells, and then a list of parts with columns of information that are specific to each part, as shown:
In the master sheet, I want a separate line for each part that includes the general information as well as the specific part information, as shown:
I have created a loop that pulls all the information I want, but all the information is written as a single line in the master sheet, as shown:
Can anyone tell me how to create a separate line for each item? The code I have pieced together is shown- I think the solution to my problem lies in how to format the section titled "change this range to fit your own needs"
Sub MergeNT154BatchCards()
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 dt As String
Dim bookName As String
Dim rnum As Long, CalcMode As Long
Dim a As Range, c As Range
Dim x As Long
Dim sourceRange As Range, destrange As Range
' Change this to the path\folder location of your files.
MyPath = "C:\Users\amiller\OneDrive - CoorsTek\temp"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xls*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
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)
ActiveSheet.Name = "Density"
bookName = "DensitySummary"
dt = Format(CStr(Now), "yyyy_mm_dd_hh.mm")
BaseWks.SaveAs Filename:="C:\Users\amiller\OneDrive - CoorsTek\temp\" & bookName & dt
rnum = 1
Range("A1").Value = "FileName"
Range("B1").Value = "Description"
Range("C1").Value = "WaterTemp(C)"
Range("D1").Value = "WaterDensity(g/cc)"
Range("E1").Value = "PartID"
Range("F1").Value = "DryMass(g)"
Range("G1").Value = "SuspendedMass(g)"
Range("H1").Value = "Density(g/cc)"
' Loop through all files in the myFiles array.
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
' Change this range to fit your own needs.
With mybook.Worksheets(1)
Set R1 = Range("A11, A5, B5")
Set R2 = Range("A13:D" & Range("A13").End(xlDown).Row)
Set RF = Union(R1, R2)
Set sourceRange = RF
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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 + 1, "A"). _
Resize(.Rows.Count).Value = MyFiles(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("B" & rnum + 1)
x = 0
For Each a In sourceRange.Areas
For Each c In a.Cells
x = x + 1
destrange.Offset(0, x - 1).Value = c.Value
Next c
Next a
' 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
End Sub
I'm slightly worried because the headings you seem to be writing to the master sheet don't seem to line up with the data, and because you seem to be only copying Range("A11, A5, B5") from the top part of each sheet but your images show 5 fields being taken from the top, but I think you can replace your For FNum loop with the following:
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
With mybook.Worksheets(1)
Set SourceRange = .Range("A13:D" & .Range("A13").End(xlDown).Row)
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.
BaseWks.Cells(rnum + 1, "A").Resize(SourceRcount).Value = MyFiles(FNum)
' Copy information such as date/time started, start/final temp, and Batch ID
BaseWks.Cells(rnum + 1, "B").Resize(SourceRcount).Value = .Range("A4").Value
BaseWks.Cells(rnum + 1, "C").Resize(SourceRcount).Value = .Range("B4").Value
BaseWks.Cells(rnum + 1, "D").Resize(SourceRcount).Value = .Range("A5").Value
BaseWks.Cells(rnum + 1, "E").Resize(SourceRcount).Value = .Range("A5").Value
BaseWks.Cells(rnum + 1, "F").Resize(SourceRcount).Value = .Range("A11").Value
'Copy main data
BaseWks.Cells(rnum + 1, "G").Resize(SourceRcount, SourceRange.Columns.Count).Value = SourceRange.Value
rnum = rnum + SourceRcount
End If
End With
End If
mybook.Close savechanges:=False
Next FNum
The root of your problem is that you are trying to do too much in a single subroutine. Whenever your subroutines are over 25-40 lines, you should consider extracting functionality into smaller subroutines. In this way, you will be able to test smaller portions of code at a time.
By implementing this strategy, I managed to reduce the OPs original subroutine from 152 lines of code to 5 easy to debug subroutines with 80 lines of code.
MergeNT154BatchCards - Main subroutine
AddBatchCard - Opens a Workbook and adds new rows of data to a range
getDensityTemplate - Creates a new Workbook based off a template
getFileList - Gets a list of file from a directory
ToggleEvents - Turns off and on events and returns the current Calculation mode
I haven't tested some parts of the code and as #YowE3K stated the headers don't line up. I would think that it will be fairly easy to modify the code to fit the OPs requirement using these smaller blocks of code.
Public Sub MergeNT154BatchCards()
Dim vFiles As Variant, FileFullName As Variant
Dim NextRow As Range, wb As Workbook
Dim CalculationMode As XlCalculation
CalculationMode = ToggleEvents(False, xlCalculationManual)
vFiles = getFileList("C:\Users\best buy\Downloads\stackoverfow", "*.xls*")
If UBound(vFiles) = -1 Then
MsgBox "No files found", vbInformation, ""
Exit Sub
End If
Set wb = getDensityTemplate
For Each FileFullName In vFiles
With wb.Worksheets(1)
'Add Header
.Range("A1:H1").Value = Array("FileName", "Description", "WaterTemp(C)", "WaterDensity(g/cc)", "PartID", "DryMass(g)", "SuspendedMass(g)", "Density(g/cc)")
'Target the next empty row
Set NextRow = .Range("A" & .Rows.Count).End(xlUp).Offset(1)
AddBatchCard CStr(FileFullName), NextRow
End With
Next
ToggleEvents True, CalculationMode
End Sub
Private Sub AddBatchCard(FileFullName As String, NextRow As Range)
Dim cell As Range
Dim x As Long, y As Long
With Workbooks.Open(FileFullName)
With .Worksheets(1)
For Each cell In .Range("A13", .Range("A" & .Rows.Count).End(xlUp)).Value
'NextRow
NextRow.Cells(1, 1).Value = .Range("A4").Value
NextRow.Cells(1, 2).Value = .Range("B4").Value
NextRow.Cells(1, 3).Value = .Range("A5").Value
NextRow.Cells(1, 4).Value = .Range("B5").Value
NextRow.Cells(1, 4).Resize(1, 4).Value = cell.Resize(1, 4).Value
Set NextRow = NextRow.Offset(1)
Next
End With
.Close SaveChanges:=False
End With
End Sub
Private Function getDensityTemplate(FilePath As String) As Workbook
Dim SheetsInNewWorkbook As Integer
Dim wb As Workbook
SheetsInNewWorkbook = Application.SheetsInNewWorkbook
Application.SheetsInNewWorkbook = 1
Set wb = Workbooks.Add(xlWBATWorksheet)
wb.Worksheets(1).Name = "Density"
wb.SaveAs FileName:=FilePath & "DensitySummary" & Format(Now, "yyyy_mm_dd_hh.mm")
Set getDensityTemplate = wb
End Function
Private Function getFileList(FilePath As String, PatternSearch As String) As Variant
Dim FileName As String
If Right(FilePath, 1) <> "\" Then FilePath = FilePath & "\"
With CreateObject("System.Collections.ArrayList")
FileName = Dir(FilePath & PatternSearch)
Do While FileName <> ""
.Add FilePath & FileName
FileName = Dir()
Loop
getFileList = .ToArray
End With
End Function
Private Function ToggleEvents(EnabelEvents As Boolean, CalculationMode As XlCalculation) As XlCalculation
With Application
ToggleEvents = .Calculation
.Calculation = CalculationMode
.ScreenUpdating = EnabelEvents
.EnableEvents = EnabelEvents
End With
End Function

Error selecting range cells to copy from multiple work books

Updated in response to comment from dwirony:
I am trying to create a code that copies information from the same cells in multiple workbooks and combines the information into a single summary workbook. The code below works as written, however, if I add more cell address to the sourceRange (starting on line 69) the macro still runs but no information is copied into the new summary workbook.
Original Question:
I am trying to select the same specific cells from multiple worksheets within a single folder and combine them into a master spreadsheet. The code works up to a certain number of cells, but if I try to include any more, the macro returns a blank workbook (except for the column headings I've assigned). Cells that work initially will won't work if there are too many selected cells. i.e., in the code shown below, cell J2 is the first and the last cell called and the program runs. If I add J2 again, (range ends ...J2, J2")or any other cell, it appears that I've hit a limit somewhere and I get a blank workbook.
I have zero previous experience with VBA and macros, and everything I've put together comes from a variety of internet and internal sources. Maybe the multiple sources are the source of the error?
Any help would be greatly appreciated!
Sub MergeAllWorkbooks()
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
Dim a As Range, c As Range
Dim x As Long
' Change this to the path\folder location of your files.
MyPath = "C:\Users\amiller\OneDrive - CoorsTek\temp"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xls*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Set various application properties.
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 myFiles array.
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
' Change this range to fit your own needs.
With mybook.Worksheets(1)
Set sourceRange = .Range("J2, C2, D7, F7, K7, G10, J10, G11, J11, G12, J12, G14, J14, G15, J15, G16, J16, G17, J17, J21," _
& "J2, D24, E24, G24, I24, J24, O24, P24, Q24, R24, S24, D25, E25, G25, I25, J25, O25, P25, Q25, R25, S25," _
& "D26, E26, G26, I26, J26, O26, P26, Q26, R26, S26, D27, J2")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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 + 1, "A"). _
Resize(.Rows.Count).Value = MyFiles(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("B" & rnum + 1)
x = 0
For Each a In sourceRange.Areas
For Each c In a.Cells
x = x + 1
destrange.Offset(0, x - 1).Value = c.Value
Next c
Next a
' 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
End Sub

How to append data to existing workbook's sheet and don't create a new workbook

I am trying to work out what I need to change in the following VBA code to append the data at the bottom of data that already exists in a workbook named "Main" and a worksheet named "summary":
Sub MergeAllWorkbooks()
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
' Change this to the path\folder location of your files.
MyPath = "C:\test\"
' Add a slash at the end of the path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill the myFiles array with the list of Excel files
' in the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
FNum = FNum - 1
' Set various application properties.
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 myFiles array.
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
' Change this range to fit your own needs.
With mybook.Worksheets(1)
Set sourceRange = .Range("A2:T" & CStr(mybook.Worksheets(1).Range("A2").CurrentRegion.Rows.Count))
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If 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 = MyFiles(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
End Sub
Thank you
I do not like this code. There is lots I object to but I am most unhappy about the use of error handling:
The error handling functionality is there to allow your routine to fail gracefully when something goes wrong. It is not there to allow you to ignore errors and carry on as though they did not happen.
The error handling failed to handle a problem with one of my workbooks. I have not investigated but I suspect the problem is either the length of a single cell or the total length of the data being transferred by destrange.Value = sourceRange.Value.
However, you ask how to make a single change so I will limit myself to that.
I suggest the easiest approach would be to create workbook "Main" with worksheet "Summary" and to include your macro in it.
Add new statements under the Dim statements:
Dim rnum As Long, CalcMode As Long
'### Start of new code
If Workbooks.Count > 1 Then
' It is easy to get into a muddle if there are multiple workbooks
' open at the start of a macro like this. Avoid the problem until
' you understand it.
Call MsgBox("Please close all other workbooks", vbOKOnly)
Exit Sub
End If
Set BaseWks = ActiveWorkBook.Worksheets("Summary")
With BaseWks
rnum = .Cells(Rows.Count, "A").End(xlUp).Row + 1
End With
'### End of new code
' Change this to the path\folder location of your files.
The first block of the above code ensures there are no other workbooks open.
The second block (1) sets BaseWks to worksheet "Summary" and (2) sets rnum to the first unused row in "Summary". End(xlUp) is the VBA equivalent of clicking Ctrl+Up. So I have gone to the bottom of column A, gone up until I hit a row with a value and then down 1 row.
Replace the loop that locates the filenames with:
Do While FilesInPath <> ""
If FilesInPath <> ActiveWorkbook.Name Then
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
End If
FilesInPath = Dir()
Loop
I assume that workbook "Main" will be in the same folder as the other workbooks. This change ensures that "Main" is not used as a source.
Discard these statements:
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
because I have already set BaseWks and rnum to the values I require.
If you want to save the updated workbook "Main" automatically, add the following statement above ExitTheSub::
ActiveWorkbook.Save