How to make a "copy-paste" macro run faster? - excel

I have written a macro in Excel VBA that basically copy-pastes 53 rows 1440 times, one under another, in order to populate two columns in a ~70000 row table. The macro works, but it takes about five minutes to run completely. This would be fine if I didn't have to run this on ~1000 other files. I am looking for any way to speed up this process so that it doesn't take 5 days to run.
I tried using the range copy method:
Set range1 = {the table I'm copying}
Set range2 = {the cells I want to paste into}
range1.Copy range2
but it took just as long, if not longer.
Here is my current code:
Windows("as_built_comp.xlsm").Activate
Sheets(siteName).Activate
j = Cells(Rows.Count, 1).End(xlUp).Row
Range("C2").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
wb.Activate
Range("I12").Select
For i = 1 To 1440
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone,
SkipBlanks _
:=False, Transpose:=False
ActiveWindow.SmallScroll Down:=56
ActiveCell.Offset(j - 1, 0).Select
Next i
I'm thinking the solution might have something to do with using sql in VBA, but I have yet to learn that syntax. Either way, any advice is greatly appreciated. Thank you for reading!

Load it all into an array and then output the entire array at the end. Code refactored to avoid the use of activate/select
Sub tgr()
Dim wbDest As Workbook
Dim wbData As Workbook
Dim wsDest As Worksheet
Dim wsData As Worksheet
Dim aTemp() As Variant
Dim aData() As Variant
Dim SiteName As String
Dim RepeatData As Long
Dim ixTemp As Long
Dim ixData As Long
Dim ixCol As Long
SiteName = "SiteName1"
RepeatData = 1440
Set wbDest = ThisWorkbook
Set wbData = Workbooks("as_built_comp.xlsm")
Set wsDest = wbDest.Worksheets(1)
Set wsData = wbData.Worksheets(SiteName)
With wsData.Range("C2:D" & wsData.Cells(wsData.Rows.Count, "C").End(xlUp).Row)
If .Row < 2 Then Exit Sub 'No data
aTemp = .Value
ReDim aData(1 To .Rows.Count * RepeatData, 1 To .Columns.Count)
End With
For ixData = 1 To UBound(aData, 1)
ixTemp = ((ixData - 1) Mod UBound(aTemp, 1)) + 1
For ixCol = 1 To UBound(aTemp, 2)
aData(ixData, ixCol) = aTemp(ixTemp, ixCol)
Next ixCol
Next ixData
wsDest.Range("I12").Resize(UBound(aData, 1), UBound(aData, 2)).Value = aData
End Sub

Related

Selected range of cells via VBA doesn't work

EDITED
I would like to ask you for help & revision of my VBA code as I am new to VBA.
I have pivot table with 3 columns. Via slicer I choose the items I want to add in new data table, each item must be added 3 times - therefore in the code I used loop 3 times.
The VBA works perfectly when 2 or more items are chosen.
However, when only single item is selected, the VBA crashes because the "selected copied range" does not have the same size as "pasted range" size. Basically, it selects all cells from column "F2:H2" until the end of spreadsheet.
Sub Copy()
Dim i
For i = 1 To 3
StartRange = "F2:H2"
EndRange = "F2:H2"
Set a = Range(StartRange, Range(StartRange).End(xlDown))
Set b = Range(EndRange, Range(EndRange).End(xlDown))
Union(a, b).Select
Selection.Copy
lastrow = ActiveSheet.Cells(Rows.Count, "T").End(xlUp).Row + 1
Cells(lastrow, "T").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Next i
End Sub
How to modify the code, if only single item is selected, it will copy the cells in new data table as well?
I can provide a test file for reference.
Use .End(xlDown) from the header row.
Option Explicit
Sub Copy()
Dim ws As Worksheet, rng As Range
Dim i As Long, lastrow As Long
Set ws = ThisWorkbook.ActiveSheet
Set rng = ws.Range("F2", ws.Range("H1").End(xlDown))
For i = 1 To 3
lastrow = ws.Cells(Rows.Count, "T").End(xlUp).Row + 1
rng.Copy
ws.Cells(lastrow, "T").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Next i
End Sub
or to copy single rows
Sub Copy2()
Const REPEAT = 3
Dim ws As Worksheet, rng As Range
Dim row As Range, lastrow As Long
Set ws = ThisWorkbook.ActiveSheet
Set rng = ws.Range("F2", ws.Range("H1").End(xlDown))
lastrow = ws.Cells(Rows.Count, "T").End(xlUp).row + 1
For Each row In rng.Rows
If Not row.Hidden Then
ws.Cells(lastrow, "T").Resize(REPEAT, row.Columns.Count).Value = row.Value
lastrow = lastrow + REPEAT
End If
Next
End Sub

Properly looping through non-contiguous ranges?

I have a few non-contiguous ranges that may vary in size each time it is run. I would like to take each of the ranges and copy and paste them onto their own individual worksheets (one range per sheet).
My code currently works for the first range and sheet. After the second sheet is created, the ranges are highlighted, but the first range is again copied and pasted onto the second sheet, instead of the corresponding second range. Then, the third sheet is created, but again, only the first range is copied and pasted onto this sheet. I know something is wrong with my looping, but I can't figure out where.
I have exhausted all of my resources. I just can't figure out why the loop isn't getting to the other 2 ranges.
'Get current sheet name
Dim activeSheetName As String
activeSheetName = ActiveSheet.Name
'Create a new sheet to reformat existing data
Dim newSheetName As String
newSheetName = (activeSheetName + "_Data")
Dim filterRange As range
Dim areasCount As Integer
For Each a In filterRange.Areas
Sheets(newSheetName).Select
filterRange.Select
range(Selection, Selection.End(xlToRight)).Select
areasCount = Selection.Areas.Count
With a
For i = 2 To areasCount + 1
Selection.Copy
With Sheets.Add(After:=Sheets(Sheets.Count))
.Name = a.Cells(1, 1).Value
.range("A1").Value = a.Offset(, 1)
range("A50").Select
Selection.PasteSpecial paste:=xlPasteAll, Operation:=xlNone, _
SkipBlanks:= False, Transpose:=False
Application.CutCopyMode = False
End With
Next i
End With
Next a
I have tried to incorporate the following code I found in a book, but no such luck.
Dim SelAreas() As range
Dim pasteRange As range
Dim upperLeft As range
Dim numAreas As Long, i As Long
Dim topRow As Long, leftCol As Long
Dim rowOffset As Long, colOffset As Long
If TypeName(Selection) <> "Range" Then Exit Function
numAreas = Selection.Areas.Count
ReDim SelAreas(1 To numAreas)
For i = 1 To numAreas
Set SelAreas(i) = Selection.Areas(i)
Next
topRow = ActiveSheet.Rows.Count
leftCol = ActiveSheet.Columns.Count
For i = 1 To numAreas
If SelAreas(i).Row < topRow Then topRow = SelAreas(i).Row
If SelAreas(i).Column < leftCol Then leftCol = SelAreas(i).Column
Next
Set upperLeft = Cells(topRow, leftCol)
On Error Resume Next
Set pasteRange = range("A50")
On Error GoTo 0
If TypeName(pasteRange) <> "Range" Then Exit Function
Set pasteRange = pasteRange.range("A1")
For i = 1 To numAreas
rowOffset = SelAreas(i).Row - topRow
colOffset = SelAreas(i).Column - leftCol
SelAreas(i).Copy
range("A1").Value = pasteRange.Offset(rowOffset, colOffset)
Next i
For Each a In filterRange.Areas
Sheets(newSheetName).Select
range(a, a.End(xlToRight)).Copy
With a
If filterRange Is Nothing Then
MsgBox ("Value not present in this workbook.")
Else
With Sheets.Add(After:=Sheets(Sheets.Count))
.Name = a.Cells(1, 1).Value
.range("A1").Value = a.Offset(, 1)
range("A50").Select
ActiveSheet.paste
End With
range("A10:A49").Select
range(Selection, Selection.End(xlToRight)).Select
Selection.Delete
range("A1").Select
End If
End With
Next a

Transfer(copy&paste) data from one tab to another with transpose in #vba

First of all, I'm new in VBA. Basically, I want to transfer data from one tab to another(within one doc) and paste them transposed.
The code I have here, allows me to move to the next row, after submitting data for the first person.
Sub Submit()
Dim rngSource As Range
Dim rngTarget As Range
Dim iRow As Integer
'tranferring data between macro
Set rngSource = Worksheets("Checklist").Range("b1:b5")
'figuring out the empty row
iRow = Worksheets("Central Tracker").Cells(Rows.Count, 1).End(xlUp).Row + 1
Set rngTarget = Worksheets("Central Tracker").Range("A" & iRow)
rngSource.Copy Destination:=rngTarget.PasteSpecial Paste:= xlPasteValues
End Sub
Basically, I want to add in the transposed paste option but I don't know how I can do that. I will really appreciate your support. Thanks!
Just use Transpose:=True
Dim rngSource As Range
Dim rngTarget As Range
Dim iRow As Integer
'tranferring data between macro
Set rngSource = Worksheets("Checklist").Range("b1:b5")
'figuring out the empty row
iRow = Worksheets("Central Tracker").Cells(Rows.Count, 1).End(xlUp).Row + 1
Set rngTarget = Worksheets("Central Tracker").Range("A" & iRow)
rngSource.Copy
rngTarget.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=True

need to remove empty rows from Excel table and then resize the table - using VBA

I wrote a macro (mostly by recording it) that copies data from a section on one sheet then calculates the end of my table on another sheet and pastes (paste special, being that the data I am pasting is a formula and I need to paste the values) the data to the end of my table, which on its own increases the size of my table.
That works.
My problem is that I am not sure how much of my original range of data (that I am copying) will actually have values in it (there is a formula that is either giving it a value or ""), so I take a large range, just in case
So.... after I pasted it I would like to go through my table and remove any rows that were added that only had empty strings ("") and no values, and then resize the table so it is only as large as the rows that have data.
These rows can be in the middle or at the end of my pasted data.
I need help on the VBA code to do that.
I may also need to clear the formatting that the table automatically added to those additional rows
here is the code I have until now
Range("O7:R30").Select
Selection.Copy
Sheets("deposits").Select
Dim lastRow As Long
lastRow = ActiveSheet.ListObjects("deposits").Range.Rows.Count
Range("A" & lastRow).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Probably best to only place data into the table if its valid, rather than clean up after the paste.
Something like this
Sub Demo()
Dim rDest As Range
Dim lo As ListObject
Dim wsSrc As Worksheet
Dim rSrc As Variant
Dim i As Long
Dim rng As Range
'there are better ways to get a reference to the source data, but thats not the Q here
Set wsSrc = ActiveSheet
Set rSrc = wsSrc.Range("O7:R30")
' destination sheet
With Sheets("deposits")
'get reference to table
Set lo = .ListObjects("deposits")
'Get reference to first row after the table
Set rDest = lo.DataBodyRange.Rows(lo.DataBodyRange.Rows.Count + 1)
i = 0
'loop thru source data rows
For Each rng In rSrc.Rows
'if a row has data
If Application.WorksheetFunction.CountA(rng) > 0 Then
'copy values into table
rDest.Offset(i).Value = rng.Value
i = i + 1
End If
Next
End With
End Sub
This code worked, not elegant, but it worked
Sub copyToDeposits()
Dim theSheet As String
theSheet = ActiveSheet.Name
Application.ScreenUpdating = False
Range("O7:R30").Select
Selection.Copy
Sheets("deposits").Select
Dim lastRow As Long
lastRow = ActiveSheet.ListObjects("deposits").Range.Rows.Count
Range("A" & lastRow).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Dim lo As ListObject
Dim lRow As ListRow
Dim rng As Range
Dim delRows As Collection
Set lo = ActiveSheet.ListObjects("deposits") 'change to your table name
On Error Resume Next
For Each lRow In lo.ListRows
Set rng = Nothing
Set rng = lRow.Range.Cells(1, 2)
If Not rng Is Nothing Then
If rng = "" Then
If delRows Is Nothing Then
Set delRows = New Collection
delRows.Add lRow
Else
delRows.Add lRow, Before:=1
End If
End If
End If
Next
On Error GoTo 0
If Not delRows Is Nothing Then
For Each lRow In delRows
lRow.Delete
Next
End If
Sheets(theSheet).Select
Application.ScreenUpdating = True
End Sub

to open workbook from an array

this is my code where users can select multiple files and then they are compared with headers in master file and then data is copy pasted. the problem is that i do not know how to reference the workbooks from the array to run the code, one workbook at a time. previously for a single workbook i used the activate statement but i do not know how to do it for multiple workbooks in the array. the book names are stored in arrNames. Temp calc is the sheet where all the data has to be stored. any suggestions ?
thanks,
Mathew
Sub Test()
Dim lastCol, lastRow As Long, k As Long, a As Variant, b As Variant, cmpRng As Range
Dim mastCol As Long, mastRng As Range, n As Long
Dim Wbk As Workbook
Dim fileone
Dim SelectedFiles As Object
Dim arrNames As Variant
Dim indx As Long
Application.ScreenUpdating = False
Sheets("Temp Calc").Select
'Clear existing sheet data except headers
Rows(1).Offset(1, 0).Resize(Rows.Count - 1).ClearContents
arrNames = Application.GetOpenFilename(Filefilter:="Workbooks (*.xlsx),*.xlsx", MultiSelect:=True)
For i = 1 To UBound(arrNames, 1)
Worksheets("Temp Calc").Select
lastCol = Worksheets("Temp Calc").Cells(1, Columns.Count).End(xlToLeft).Column
lastRow = Worksheets("Temp Calc").Cells(Rows.Count, 1).End(xlDown).Row
Set cmpRng = Range(Cells(1, 1), Cells(1, lastCol))
a = cmpRng
mastCol = Cells(1, Columns.Count).End(xlToLeft).Column
Set mastRng = Range(Cells(1, 1), Cells(1, mastCol))
b = mastRng
For k = 1 To lastCol
For n = 1 To mastCol
If UCase(a(1, k)) = UCase(b(1, n)) Then
Here i need the code to open workbook in array
Worksheets("Sheet1").Range(Cells(2, n), Cells(lastRow, n)).Copy
Windows("Dashboard_for_Roshan.xlsm").Activate
Worksheets("Temp Calc").Select
Cells(2, k).PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
Exit For
End If
Next
Next
Next
'Else
'End If
Application.ScreenUpdating = True
Exit Sub
'Next
End Sub
you could try
sPath="C:\"
workbooks(sPath & arrNames(i)).open
where i is your loop counter through the array returned by GetOpenFileName and arrNames is your array

Resources