Combine 2 codes with loops into 1 single code - excel

After various trial and errors and helps from this forum, I managed to come out with the following codes to achieve what I want but it's two vba loops. I am hit with bottleneck on how to combine these two vba with loops into 1 single vba.
Here is my code.
Sub Macro1()
'
' Macro1 Macro
'
Dim WS_Count As Integer
Dim I As Integer
WS_Count = ActiveWorkbook.Worksheets.Count
For I = 1 To WS_Count
Sheets(I).Select
Range("B11").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Range("B11").Select
ActiveCell.FormulaR1C1 = "Outlet name"
Range("C11").Select
ActiveCell.FormulaR1C1 = "PO Number"
Range("D11").Select
ActiveCell.FormulaR1C1 = "PO Date"
Range("E11").Select
ActiveCell.FormulaR1C1 = "Delivery Date"
' Copy outlet name
Range("B1").Select
Selection.Copy
Range("A12").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 1).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Select
ActiveSheet.Paste
' Copy PO number
Range("B2").Select
Selection.Copy
Range("A12").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 2).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Select
ActiveSheet.Paste
' Copy PO date
Range("B3").Select
Selection.Copy
Range("A12").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 3).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Select
ActiveSheet.Paste
' Copy DO date
Range("B4").Select
Selection.Copy
Range("A12").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 4).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Select
ActiveSheet.Paste
Next I
Exit Sub
End Sub
Here is the second vba.
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
Sub Marco2()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
Last = LastRow(DestSh)
Set CopyRng = sh.Range("A12").Offset(1).CurrentRegion
Set CopyRng = CopyRng.Offset(1, 0)
Set CopyRng = CopyRng.Resize(CopyRng.Rows.Count - 1)
CopyRng.Copy
'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
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
Thank you for your valuable time to read through this.
Cheers

Without explanation, it's unclear what this code is supposed to do, but I cleaned it up a little bit anyhow.
Create a separate procedure to run these two sub's in whichever order you need them to run. For example:
Sub runMyThings()
Call Macro1
Call Macro2
End Sub
Note that I changed the name of Marco2 to Macro2, but you should probably give them more meaningful names than that. (Otherwise it's like having all your files called File.)
Option Explicit
Sub Macro1()
Dim i As Integer
For i = 1 To ActiveWorkbook.Worksheets.Count
Sheets(i).Range("B11").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Selection.Insert Shift:=xlToRight
Range("B11").FormulaR1C1 = "Outlet name"
Range("C11").FormulaR1C1 = "PO Number"
Range("D11").FormulaR1C1 = "PO Date"
Range("E11").FormulaR1C1 = "Delivery Date"
' Copy outlet name
Range("B1").Copy
Range("A12").End(xlDown).Offset(0, 1).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Paste
' Copy PO number
Range("B2").Copy
Range("A12").End(xlDown).Offset(0, 2).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Paste
' Copy PO date
Range("B3").Copy
Range("A12").End(xlDown).Offset(0, 3).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Paste
' Copy DO date
Range("B4").Copy
Range("A12").End(xlDown).Offset(0, 4).Select
Range(Selection, Selection.End(xlUp).Offset(1)).Paste
Next i
End Sub
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
Sub Macro2()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
On Error Resume Next 'this will delete the Sheet WITHOUT WARNING.
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
Application.DisplayAlerts = True
On Error GoTo 0
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
Last = LastRow(DestSh)
Set CopyRng = sh.Range("A12").Offset(1).CurrentRegion
Set CopyRng = CopyRng.Offset(1, 0)
Set CopyRng = CopyRng.Resize(CopyRng.Rows.Count - 1)
CopyRng.Copy
'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
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
I'm not proud of leaving the code like this but without a better idea of what you're trying to do, I can't do anything more. (And if it doesn't work now, revert to your previous code.)

I attempted to refactor your code some to eliminate most of the select statements and combine various offsets and endup's and enddown's. (You should check that the combined results are still what you expect.)
Sub Macro1()
Dim WS_Count As Integer
Dim I As Integer
WS_Count = ActiveWorkbook.Worksheets.Count 'ThisWorkbook (?)
For I = 1 To WS_Count
with Sheets(I)
.Range(.Range("B11"), .Range("B11").End(xlDown).Offset(0,4)).Insert Shift:=xlToRight
.Range("B11").FormulaR1C1 = "Outlet name"
.Range("C11").FormulaR1C1 = "PO Number"
.Range("D11").FormulaR1C1 = "PO Date"
.Range("E11").FormulaR1C1 = "Delivery Date"
' Copy outlet name
.Range("B1").Copy
.Range(.Range("A12").End(xlDown).Offset(0, 1), .Range("A12").Offset(1, 1).End(xlUp)).Paste
' Copy PO number
.Range("B2").Copy
.Range(.Range("A12").End(xlDown).Offset(0, 2), .Range("A12").Offset(1, 2).End(xlUp)).Paste
' Copy PO date
.Range("B3").Copy
.Range(.Range("A12").End(xlDown).Offset(0, 3), .Range("A12").Offset(1, 3).End(xlUp)).Paste
' Copy DO date
.Range("B4").Copy
.Range(.Range("A12").End(xlDown).Offset(0, 4), .Range("A12").Offset(1, 4).End(xlUp)).Paste
end with
Next I
End Sub
I added some commentary to the following sub as well:
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
Sub Marco2()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
'If the sheet is always being deleted from the workbook which holds this code, the following line should be:
'ThisWorkbook.Worksheets("RDBMergeSheet").Delete
'That way, if multiple books are open, it won't try to delete from the wrong workbook
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set DestSh = ActiveWorkbook.Worksheets.Add 'ThisWorkbook (?)
DestSh.Name = "RDBMergeSheet"
For Each sh In ActiveWorkbook.Worksheets 'ThisWorkbook (?)
If sh.Name <> DestSh.Name Then
Last = LastRow(DestSh)
Set CopyRng = sh.Range("A12").Offset(1).CurrentRegion
Set CopyRng = CopyRng.Offset(1, 0).Resize(CopyRng.Rows.Count - 1)
CopyRng.Copy
'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
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 sh 'added sh to be more explicit on which loop this is for
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
Answer
I noticed that both subs loop through the worksheets in the workbook, so you should be able to combine the two by taking the code from within one sheet-loop and inserting it into the other, like so:
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
Sub Marco2()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
'If the sheet is always being deleted from the workbook which holds this code, the following line should be:
'ThisWorkbook.Worksheets("RDBMergeSheet").Delete
'That way, if multiple books are open, it won't try to delete from the wrong workbook
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set DestSh = ActiveWorkbook.Worksheets.Add 'ThisWorkbook (?)
DestSh.Name = "RDBMergeSheet"
For Each sh In ActiveWorkbook.Worksheets 'ThisWorkbook (?)
-------------------------------------------------------------
| 'From Macro1
| with sh
| .Range(.Range("B11"), .Range("B11").End(xlDown).Offset(0,4)).Insert Shift:=xlToRight
| .Range("B11").FormulaR1C1 = "Outlet name"
| .Range("C11").FormulaR1C1 = "PO Number"
| .Range("D11").FormulaR1C1 = "PO Date"
| .Range("E11").FormulaR1C1 = "Delivery Date"
|
| ' Copy outlet name
| .Range("B1").Copy
| .Range(.Range("A12").End(xlDown).Offset(0, 1), .Range("A12").Offset(1, 1).End(xlUp)).Paste
|
| ' Copy PO number
| .Range("B2").Copy
| .Range(.Range("A12").End(xlDown).Offset(0, 2), .Range("A12").Offset(1, 2).End(xlUp)).Paste
|
| ' Copy PO date
| .Range("B3").Copy
| .Range(.Range("A12").End(xlDown).Offset(0, 3), .Range("A12").Offset(1, 3).End(xlUp)).Paste
|
| ' Copy DO date
| .Range("B4").Copy
| .Range(.Range("A12").End(xlDown).Offset(0, 4), .Range("A12").Offset(1, 4).End(xlUp)).Paste
| End With
| 'End of from Macro1
----------------------------------------------------------
If sh.Name <> DestSh.Name Then
Last = LastRow(DestSh)
Set CopyRng = sh.Range("A12").Offset(1).CurrentRegion
Set CopyRng = CopyRng.Offset(1, 0).Resize(CopyRng.Rows.Count - 1)
CopyRng.Copy
'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
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 sh 'added sh to be more explicit on which loop this is for
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

Related

Excel VBA will not close my opened workbook

I am pretty much new to VBA and have been trying to learn, with this I have created a code that opens another work book and combines all data to a database file and then copy this to my current open file, the problem I have is that it will not close the workbook and takes a long time doing so. Any ideas please?.
'''
Option Explicit
Sub GasStockReport()
Dim wb As String
Dim st As String
Dim path As String
path = "C:\Users\si2066\OneDrive - ENGIE\Desktop\MP Templates\MP - Stock Control\"
wb = "Gas Stock Take v2"
Workbooks.Open path & wb
Dim sh As Worksheet
Dim destsh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Database").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set destsh = ActiveWorkbook.Worksheets.Add
destsh.Name = "Database"
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> destsh.Name Then
Last = GetLastRow(destsh, 1)
With sh
Set CopyRng = sh.Range("A2:K" & GetLastRow(sh, 1))
End With
If Last + CopyRng.Rows.Count > destsh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
Else
CopyRng.Copy IIf(Last = 1, destsh.Cells(1, "b"), destsh.Cells(Last + 1, "b"))
End If
If Last = 1 Then
destsh.Cells(Last, "A").Resize(CopyRng.Rows.Count).Value = sh.Name
Else
destsh.Cells(Last + 1, "A").Resize(CopyRng.Rows.Count).Value = sh.Name
End If
End If
Next
ExitTheSub:
Application.Goto destsh.Cells(1)
destsh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
Range("A1").Select
Range(Selection, ActiveCell.End(xlDown).End(xlToRight)).Select
Selection.Copy
ActiveWindow.SelectedSheets.Visible = False
ThisWorkbook.Sheets("Stock History").Activate
Range("N1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.DisplayAlerts = False
On Error Resume Next
Workbooks("Gas Stock Take v2").Close SaveChanges:=True
On Error GoTo 0
Application.DisplayAlerts = True
ThisWorkbook.Sheets("Stock Take").Activate
Call Click
End Sub
Public Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1)
As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function
'''
Your error handling is fine. Using On Error GoTo 0 turns off On Error Resume Next.
I think the issue is the amount of data you're leaving on the clipboard after copy and paste. If you use .copy and .paste always follow that up with Application.CutCopyMode = False

Copy multiple sheets in a workbook to a summary sheet based on autofilter criteria

I have a code that is not working in copying data from multiple sheets into a single one based on autofilter criteria.
I have this code and it is copying the data from different sheets but on applying autofilter condition it stops working
Sub CopyDataWithoutHeaders()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim shLast As Long
Dim CopyRng As Range
Dim StartRow As Long
Dim WSNew As Worksheet
Dim MyRange As Range
Dim my_range As Range
Dim Rng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Add a worksheet
'Set DestSh = ActiveWorkbook.Worksheets.Add
Set DestSh = ActiveWorkbook.Worksheets("Sheet16")
'DestSh.Name = "Destination"
'Fill in the start row
StartRow = 2
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If IsError(Application.Match(sh.Name, _
Array(DestSh.Name, "Format", "Lookups"), 0)) And sh.Visible = True Then
'Find the last row with data on the DestSh and sh
Last = LastRow(DestSh)
shLast = LastRow(sh)
MsgBox sh.Name
Set my_range = Range("A1:ZZ" & LastRow(ActiveSheet))
my_range.Parent.Select
'If sh is not empty and if the last row >= StartRow copy the CopyRng
If shLast >= StartRow Then
my_range.Parent.AutoFilterMode = False
ActiveSheet.Range("A1").AutoFilter Field:=22, Criteria1:="=Ready to import"
'ActiveSheet.AutoFilter.Range.Offset(1, 0).Rows.SpecialCells(xlCellTypeVisible).Copy
With my_range.Parent.AutoFilter.Range
Set Rng = .Offset(1, 0).Resize(.Rows.Count, .Columns.Count) _
.SpecialCells(xlCellTypeVisible)
MsgBox my_range
If Not Rng Is Nothing Then
'Copy and paste the cells into DestSh below the existing data
Rng.Copy
With DestSh.Range("A" & LastRow(DestSh) + 1)
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
' Intersect(.UsedRange, .UsedRange.Offset(1)).SpecialCells(xlCellTypeVisible).Copy
' DestSh.Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial xlPasteValues
MsgBox Last
' With DestSh.Cells(Last + 1, "A")
' .PasteSpecial Paste:=8
' .PasteSpecial xlPasteValues
' .PasteSpecial xlPasteFormats
' Application.CutCopyMode = False
' .Select
' End With
' End If
'Close AutoFilter
my_range.Parent.AutoFilterMode = False
'Set the range that you want to copy
' Set CopyRng = sh.Range(sh.Rows(StartRow), sh.Rows(shLast))
'Test if there enough rows in the DestSh to copy all the data
' If Last + MyRange.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 below example 1 on this page
' CopyRng.Copy
' With DestSh.Cells(Last + 1, "A")
' .PasteSpecial xlPasteValues
' .PasteSpecial xlPasteFormats
' Application.CutCopyMode = False
End With
End If
'End If
'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
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
The sheets should be copied one below another if they match the criteria.
This is basic code does what you are trying to accomplish.
Sub CopyDataWithoutHeaders()
Dim ws As Worksheet, DestSh As Worksheet, Rng As Range
Set DestSh = ThisWorkbook.Sheets("Sheet16")
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
For Each ws In ThisWorkbook.Sheets
If ws.Name <> "Format" And ws.Name <> "Lookups" And ws.Name <> DestSh.Name Then
'the below line will not select the complete range if a cell is empty in column 1
'it can be changed to the way you want.
Set Rng = ws.Range("A1", ws.Range("A1").End(xlDown).End(xlToRight))
With Rng 'will copy all the range except the header row
.AutoFilter Field:=22, Criteria1:="Ready to import", Operator:=xlAnd
.Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy
End With
'test if the first cell is empty before pasting
If DestSh.Range("A1") = "" Then
DestSh.Cells(Rows.Count, "A").End(xlUp).PasteSpecial xlPasteValues
Else: DestSh.Cells(Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
End If
'clean up each worksheet
ws.AutoFilterMode = False
Application.CutCopyMode = False
Next ws
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Thank you for the help
Issue Solved
Sub CopyDataWithoutHeaders()
Dim ws As Worksheet, DestSh As Worksheet, Rng As Range
Set DestSh = ThisWorkbook.Sheets("All")
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
For Each ws In ThisWorkbook.Sheets
If ws.Name <> "Format" And ws.Name <> "Lookups" And ws.Name <> DestSh.Name Then
Set Rng = ws.UsedRange
With Rng 'will copy all the range except the header row
.AutoFilter Field:=22, Criteria1:="Ready to import", Operator:=xlAnd
***If (ws.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count > 1)*** Then
.Offset(1, 0).Resize(Rng.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy
DestSh.Cells(Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
End With
End If
'clean up each worksheet
ws.AutoFilterMode = False
Application.CutCopyMode = False
Next ws
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
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

VBA code has too many loops which makes it run slower

I have a VBA code which copies same data from Multiple sheet and then paste it in "Main" Sheet. It then auto fills the blank cells for values from above and then it delete all the rows Where H:H is blank. However being novice in VBA, i feel my code has too many loops, which makes it run slower. Moreover if have the "Main" Sheet have a table formatted, the code does not delete any row H is blank. However it works if "Main" is blank and not formatted.
Another thing I found out that after the code is executed, the excel sheet becomes less responsive. I cannot select cells quickly, change between sheets.
Please advise if anything can be improved to make it run more efficiently.
Private Sub CopyRangeFromMultiWorksheets1()
'Fill in the range that you want to copy
'Set CopyRng = sh.Range("A1:G1")
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim rng As Range
Dim Last As Long
Dim CopyRng1 As Range
Dim CopyRng2 As Range
Dim CopyRng3 As Range
Dim CopyRng4 As Range
Dim CopyRng5 As Range
Dim CopyRng6 As Range
Dim CopyRng7 As Range
Dim cell As Range
Dim Row As Range
Dim LastrowDelete As Long
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 = Sheets("Main")
'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 And sh.Name <> "PAYPERIOD" And sh.Name <>
"TECHTeamList" Then
'Find the last row with data on the DestSh
Last = LastRow(DestSh)
'Fill in the range that you want to copy
Set CopyRng1 = sh.Range("B3")
Set CopyRng2 = sh.Range("C3")
Set CopyRng3 = sh.Range("D3")
Set CopyRng4 = sh.Range("G3")
Set CopyRng5 = sh.Range("C5")
Set CopyRng6 = sh.Range("A8:j25")
Set CopyRng7 = sh.Range("A28:j45")
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng1.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
CopyRng1.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng2.Copy
With DestSh.Cells(Last + 1, "B")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng3.Copy
With DestSh.Cells(Last + 1, "C")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng4.Copy
With DestSh.Cells(Last + 1, "D")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng5.Copy
With DestSh.Cells(Last + 1, "E")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng6.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
'Refresh the Lastrow used so that the values start from
'underneath copyrng6
Last = LastRow(DestSh)
CopyRng7.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
'Autofill the rang A2:E for values from above looking at the last row of F
With Range("A2:E" & Range("F" & Rows.Count).End(xlUp).Row)
.SpecialCells(xlBlanks).FormulaR1C1 = "=R[-1]C"
.Value = .Value
End With
'Delete Entire rows where H is Blank
Application.ScreenUpdating = False
Columns("H:H").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
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
Any Help would be appreciated.

Excel copying from multiple sheets not working vba

I have assembled this code together to copy different ranges from multiple sheets to master sheet. However for copyRng 7, instead of going underneath the copyrng6, it overwrites copyrng6.
Sub CopyRangeFromMultiWorksheets()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng1 As Range
Dim CopyRng2 As Range
Dim CopyRng3 As Range
Dim CopyRng4 As Range
Dim CopyRng5 As Range
Dim CopyRng6 As Range
Dim CopyRng7 As Range
Dim cell As Range
Dim Row As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
Set DestSh = Sheets("Main")
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name And sh.Name <> "Main" And sh.Name <> "Master" Then
'Find the last row with data on the DestSh
Last = LastRow(DestSh)
'Fill in the range that you want to copy
Set CopyRng1 = sh.Range("B3")
Set CopyRng2 = sh.Range("C3")
Set CopyRng3 = sh.Range("D3")
Set CopyRng4 = sh.Range("G3")
Set CopyRng5 = sh.Range("C5")
Set CopyRng6 = sh.Range("A8:j25")
Set CopyRng7 = sh.Range("A28:j44")
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng1.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
CopyRng1.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng2.Copy
With DestSh.Cells(Last + 1, "B")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng3.Copy
With DestSh.Cells(Last + 1, "C")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng4.Copy
With DestSh.Cells(Last + 1, "D")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng5.Copy
With DestSh.Cells(Last + 1, "E")
.PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
CopyRng6.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
CopyRng7.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
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
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
Thanks in advance. This is my first question I do apologize in advance for any mistake or confusion. I can offer more explanation if asked. Thanks
refresh the last variable between 6 and 7 copy to refresh the new last row on the sheet after 6 is copied:
CopyRng6.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
last = LastRow(DestSh)
CopyRng7.Copy
With DestSh.Cells(Last + 1, "F")
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With

Combine/Append multiple data worksheets into one summary worksheet and then delete data worksheets

In my workbook I have a FrontPage sheet with a button. This button imports csv files. Each csv file is imported/copied to its own sheet (let's call them data sheets). This part is complete. In the second part I want to combine all these sheets into one summary sheet and then delete all the data sheets. The second part is almost completed. I only need to figure out how to delete the data sheets once they have been combined into the summary sheet.
Thanks!
This is the code so far:
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
Sub CopyDataWithoutHeaders()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim shLast As Long
Dim CopyRng As Range
Dim StartRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
StartRow = 2
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
Last = LastRow(DestSh)
shLast = LastRow(sh)
If shLast > 0 And shLast >= StartRow Then
Set CopyRng = sh.Range(sh.Rows(StartRow), sh.Rows(shLast))
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the " & _
"summary worksheet to place the data."
GoTo ExitTheSub
End If
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
If you give the sheets convenient names, you can simply loop through all the sheets and delete those called Data[something] for example.
For i = 1 To ActiveWorkbook.Worksheets.Count
If Left(Worksheets(i).Name, 4) = "Data" Then
Application.DisplayAlerts = False
Worksheets(i).Delete
Application.DisplayAlerts = True
End If
Next
Looks like you already have 3/4 of the code (the loop, and name check) going on.
After copying what you need to copy, just add:
Application.DisplayAlerts = False
sh.Delete
Application.DisplayAlerts = True
This deletes the worksheet and removes the requirement for the user to accept / decline the deletion.
Looks like this would go immediately after this block:
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With

Resources