VBA - How do I speed up the time to copy and paste [duplicate] - excel

This question already has answers here:
Copy from one workbook and paste into another
(2 answers)
Closed 4 years ago.
The full code is listed below, I'm copying and data from cell DB10 from the PivotTables sheet to column N in the Checklists sheet - also note that the rows in the Checklists sheet is dynamic and grows by 3018 rows each weekly...this is the part that slows down the processign time (I timed it and it takes ~8 minutes to complete processing when running the code)
This part is where things slow down:
Sheets("PivotTables").Select
Range("DB10").Select
Selection.Copy
Sheets("Checklists").Select
Dim rng As Range
NRowCount = Cells(Rows.Count, 1).End(xlUp).Offset(-3017).Row
ARowCount = Cells(Rows.Count, 1).End(xlUp).Row
For Each rng In Range("N" & NRowCount & ":N" & ARowCount)
rng.PasteSpecial xlPasteValues
Next rng
Full code:
Sub WeeklyUpdate()
Application.ScreenUpdating = False
'
' WeeklyUpdate Macro
'
'
Sheets("Checklists").Select
Dim LR As Long
LR = Range("A" & Rows.Count).End(xlUp).Row
Range("A3:M" & LR).SpecialCells(xlCellTypeVisible).Select
'
Selection.Copy
Selection.End(xlDown).Select
Selection.End(xlUp).Select
Sheets("Checklists").Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial
xlPasteValues
Sheets("Checklists").AutoFilterMode = False
Sheets("PivotTables").Select
Range("DB10").Select
Selection.Copy
Sheets("Checklists").Select
Dim rng As Range
NRowCount = Cells(Rows.Count, 1).End(xlUp).Offset(-3017).Row
ARowCount = Cells(Rows.Count, 1).End(xlUp).Row
For Each rng In Range("N" & NRowCount & ":N" & ARowCount)
rng.PasteSpecial xlPasteValues
Next rng
Sheets("Home").Select
Application.ScreenUpdating = True
End Sub

If I'm understanding correctly, you're just pasting the value in cell DB10 into the range N[NRowCount]:N[ARowCount].
Rather than doing a For loop, just try something along the lines of:
Range("N" & NRowCount & ":N" & ARowCount).Value = Range("DB10").Value
It eliminates the loop and should be immediate.
Your final code would look roughly as follows:
...
Sheets("Checklists").AutoFilterMode = False
Sheets("Checklists").Range("N" & NRowCount & ":N" & ARowCount).Value = Sheets("PivotTables").Range("DB10").Value
Sheets("Home").Select

Related

Copy data range in one sheet to another as values until a specific value arise

In below code I need to copy a range from "Output for qualifying" and insert as values in "Output".
It works, but I need the code to stop copy the range when column A start to contain the value zero (0).
Is there a smart way to do that? Hope you guys can help me.
Sub Copy_to_output()
Worksheets("Output for qualifying").Range("A2:A400").Copy
Worksheets("Output").Range("A9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("B2:H400").Copy
Worksheets("Output").Range("E9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("J2:K400").Copy
Worksheets("Output").Range("L9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("Q2:Y400").Copy
Worksheets("Output").Range("N9").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
The only thing I can think of in your situation is to use the Find method.
So, in your code, find the first 0 value, then use that as your row reference for the copy. This is by no means a clean way for the operation, but will do the task.
Sub Copy_to_output()
Dim lZeroRow As Long
lZeroRow = Worksheets("Output for qualifying").Range("A:A").Find(What:="0", LookIn:=xlValues, LookAt:=xlWhole).Row
Worksheets("Output for qualifying").Range("A2:A" & lZeroRow).Copy
Worksheets("Output").Range("A9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("B2:H" & lZeroRow).Copy
Worksheets("Output").Range("E9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("J2:K" & lZeroRow).Copy
Worksheets("Output").Range("L9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("Q2:Y" & lZeroRow).Copy
Worksheets("Output").Range("N9").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
Try the next code, please:
Sub Copy_to_output()
Dim shOFQ As Worksheet, shO As Worksheet, lastRow As Long
Set shOFQ = Worksheets("Output for qualifying")
Set shO = Worksheets("Output")
lastRow = shOFQ.Range("A:A").Find(What:="0", LookIn:=xlValues, LookAt:=xlWhole).row
shO.Range("A9").Resize(lastRow, 1).Value = shOFQ.Range("A2:A" & lastRow).Value
shO.Range("E9").Resize(lastRow, shOFQ.Range("B2:H" & lastRow).Columns.Count).Value = shOFQ.Range("B2:H" & lastRow).Value
shO.Range("L9").Resize(lastRow, shOFQ.Range("J2:K" & lastRow).Columns.Count).Value = shOFQ.Range("J2:K" & lastRow).Value
shO.Range("N9").Resize(lastRow, shOFQ.Range("Q2:Y" & lastRow).Columns.Count).Value = shOFQ.Range("Q2:Y" & lastRow).Value
End Sub
No need to use Copy Paste...

Copy/Paste last two rows into next empty row and clear certain cells (contains merged cells)

I'm trying to make a command button up the top of my sheet which when pressed will copy the last 2 rows in columns A:AJ that have data and paste into the next empty row below them. I want the source style and formulas to be copied but not the manually entered data. I have an image here too to help:
So for example from the image. I want to copy rows 105/106 together and then paste them to 107/108 as they are the next empty rows(although hidden so would also need to unhide those rows).
Everything in those 2 rows should be copied except the bottom "strokes" section and par/strokes box is a formula/date/data validation/dropdown which I want copied but the strokes section to be empty as well as date/dropdown be blank too. I would like it to all look the same as well (copy the style). Filled cells to clear in that scenario would be column B, C, E:M, P:X but only on the "STROKES" row.
To put it even more basically. I want a button to push that will add another row to the table. So I have 52 there in the picture you can see, when pressed I will now have 53 below it and it be blank ready for use.
If the hidden rows need to be unhidden for this to work I can do that.
I have looked to try do it myself but I've never done anything with VBA before so I have no idea.
I hope someone can understand this request and that it is even doable.
Thanks.
Based on DecimalTurn's answer, I made some changes and here's my new code:
Private Sub CommandButton1_Click()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear1() As Variant
Dim ListOfColumnsToClear2() As Variant
ListOfColumnsToClear1 = Array("B:C")
ListOfColumnsToClear2 = Array("E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear1) To UBound(ListOfColumnsToClear1)
Intersect(ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear1(i))).ClearContents
Next i
For i = LBound(ListOfColumnsToClear2) To UBound(ListOfColumnsToClear2)
Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear2(i))).ClearContents
Next i
End Sub
It's probably completely wrong but it did work.
To achieve what you are trying to do with VBA, I would suggest to have your code do the following (in that order):
Find the last row of data.
Define the range to copy and copy that range.
Ajust line numbering
Clear the content of the cells that need manual inputs.
Assuming you don't need to unhide any rows, the code would look like this:
Sub CopyLastTwoRows()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear() As Variant
ListOfColumnsToClear = Array("B:C", "E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear) To UBound(ListOfColumnsToClear)
Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear(i))).ClearContents
Next i
End Sub
Now, since you have merged cells, the section where we clear data will give you an error since only the bottom part of your merged cells will intersect. To solve this, we can use a function that will make sure that if there are merged cells in our range, all their cells will be included.
The code would look like this (note the new function at the end):
Sub CopyLastTwoRows()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear() As Variant
ListOfColumnsToClear = Array("B:C", "E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear) To UBound(ListOfColumnsToClear)
ExpandToIncludeMergedCells(Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear(i)))).ClearContents
Next i
End Sub
Private Function ExpandToIncludeMergedCells(ByRef Rng As Range) As Range
Dim TempRange As Range
Set TempRange = Rng.Cells(1)
Dim c As Range
For Each c In Rng
Set TempRange = Union(TempRange, c.MergeArea)
Next c
Set ExpandToIncludeMergedCells = TempRange
End Function
Finally, if you want to do this multiple times (say 10 times) by pressing a button, you would simply do:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim i As Long
For i = 1 To 10
CopyLastTwoRows
Next i
Application.ScreenUpdating = True
End Sub
Note that I'm using Application.ScreenUpdating = False to tell Excel not to refresh the screen while the macro is running. This will make your code run much faster, but it's recommended to set it back to true at the end and to have some error handling (which I didn't include here).

Transfer Data Row from Table to the bottom of another Table on different sheet

I am trying to transfer a row of data from one table to a new row at the bottom of another table when a date is entered into the cell(Column "AD").
When I try, data is transferred to the row under the last row of the table.
Sub TRANSFER_DATA()
For Each Cell In Worksheets("Sheet1").Range("AD2:AD1000")
If Cell.Value > 0 Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Cut
Sheets("Sheet2").Select
ActiveSheet.Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
End If
Next Cell
End Sub
If i understood your question you can try this code:
Execute the macro when you have the sheet1 active
Sub TRANSFER_DATA()
Dim lastrow, i As Long
Dim ADCell as Integer
ADCell=30 ' control the column AD
'control how many data there are in column A. If you want count how many rows
'with ColumnAD change 1 in 30 (lastrow = Cells(rows.count,30).End(xlUp).Row)
lastrow = Cells(rows.count, 1).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, ADCell) > 0 Then
rows(i & ":" & i).Select
Selection.Cut Worksheets("Sheet2").Range("A" & rows.count).End(xlUp).Offset(1)
End If
Next i
End Sub
I tried the code and works.
UPDATED THE POST AFTER YOUR COMMENT
Sub TRANSFER_DATA()
Dim lastrow, i, ls As Long
Dim ADCell as Integer
ADCell=30 ' control the column AD
'control how many data there are in column A. If you want count how many rows
'with ColumnAD change 1 in 30 (lastrow = Cells(rows.count,30).End(xlUp).Row)
lastrow = Cells(rows.count, 1).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, ADCell) > 0 Then
rows(i & ":" & i).Select
Selection.Cut Worksheets("Sheet2").Range("A" & rows.count).End(xlUp).Offset(1)
End If
Next i
With Sheets("sheet2")
ls = .Cells(.rows.count, ADCell).End(xlUp).Row
.ListObjects("TableName").Resize Range("$A$1:$AD$" & ls)
End With
End Sub
the updated code have another variable, ls. This variable has the number of not empty rows of sheet2. ListObjects.("name of your table") insert the new data (rows) into the table.
I hope this helps

Auto-filing Formula to Last Row of a Single Column

I need to constantly start at cell R2 and auto-fill a formula down to the last row of column R. However, the number of rows is constantly changing so I need to write a macro that finds the last row and stops their. I've tried this code but keep getting errors. Any thoughts?
Sub InvoicePrice()
Dim Lastrow As Long
Lastrow = Range("R" & Rows.Count).End(xlUp).Row
Range("R2").Select
ActiveCell.FormulaR1C1 = "=RC[-2]/RC[-4]"
Selection.AutoFill Destination:=Range("R2" & Lastrow)
The error you are getting is due to this Range("R2" & Lastrow)
The range address concatenates to R21400 if the last row was 1400. So we need to add the :R to the address.
Range("R2:R" & Lastrow)
It will now concatenate to R2:R1400
There is not need to do it with three lines, one will suffice:
Sub InvoicePrice()
Dim Lastrow As Long
Lastrow = Range("P" & Rows.Count).End(xlUp).Row
Range("R2:R" & Lastrow).FormulaR1C1 = "=RC[-2]/RC[-4]"
End Sub
Not sure if you already tried this:
Sub InvoicePrice()
Dim Lastrow As Long
Lastrow = Range("P2").End(xlDown).Row
Range("R2").Select
ActiveCell.FormulaR1C1 = "=RC[-2]/RC[-4]"
Selection.AutoFill Destination:=Range("R2" & Lastrow)
It seems to me that Range("R" & Rows.Count) locates you out of current region

Script in where it copies a sheet's data, and pastes it, but over pastes

Here is my script.
Sub Update_OOR()
Dim wsTNO As Worksheet
Dim wsTND As Worksheet
Dim wsTNA As Worksheet
Dim lastrow As Long, fstcell As Long
Set wsTNO = Sheets("Tel-Nexx OOR")
Set wsTND = Sheets("Tel-Nexx Data")
Set wsTNA = Sheets("Tel-Nexx Archive")
With Application
.ScreenUpdating = False
.DisplayAlerts = False
.EnableEvents = False
End With
With Intersect(wsTNO.UsedRange, wsTNO.Columns("S"))
.AutoFilter 1, "<>Same"
With Intersect(.Offset(2).EntireRow, .Parent.Range("B:P"))
.Copy wsTNA.Cells(Rows.Count, "B").End(xlUp).Offset(1)
.EntireRow.Delete
End With
.AutoFilter
End With
'Blow away rows that are useless
lastrow = wsTND.Range("A2").End(xlDown).Row
wsTND.Range("O1:P1").Copy wsTND.Range("O2:P" & lastrow)
wsTND.UsedRange.Copy Sheets.Add.Range("A1")
With Intersect(ActiveSheet.UsedRange, ActiveSheet.Columns("P"))
ActiveSheet.Range("O:P").Calculate
.AutoFilter 1, "<>Different"
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
With ActiveSheet
lastrow = wsTND.Range("A2").End(xlDown).Row
Intersect(.UsedRange, .Range("A2:M" & lastrow)).Copy wsTNO.Cells(Rows.Count, "B").End(xlUp).Offset(1)
.Delete
End With
With wsTNO
lastrow = wsTNO.Cells(Rows.Count, "B").End(xlUp).Row
wsTNO.Range("T1:AD1").Copy
wsTNO.Range("B3:N" & lastrow).PasteSpecial xlPasteFormats
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
fstcell = wsTNO.Cells(Rows.Count, "N").End(xlUp).Row
wsTNO.Range("AE1:AI1").Copy wsTNO.Range("O" & fstcell & ":S" & lastrow).Offset(1, 0)
End With
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.EnableEvents = True
End With
End Sub
It technically works perfectly till here:
With wsTNO
lastrow = wsTNO.Cells(Rows.Count, "B").End(xlUp).Row
wsTNO.Range("T1:AD1").Copy
wsTNO.Range("B3:N" & lastrow).PasteSpecial xlPasteFormats
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
fstcell = wsTNO.Cells(Rows.Count, "N").End(xlUp).Row
wsTNO.Range("AE1:AI1").Copy wsTNO.Range("O" & fstcell & ":S" & lastrow).Offset(1, 0)
End With
Now technically everything in this part works correctly, but the last line in the code, it pasts everything correctly, then it goes one step beyond. I'd like to know why. If I get rid of the offset it overwrites what is in the cell above in O through S. I need to know the first and last cell, because the data needs to be only written to a specific cell range.
If there is an easier way of doing this it be appreciated if someone could tell me, if not then can someone tell me how to fix this?
Thanks.
Attached is the workbook.
http://dl.dropbox.com/u/3327208/Excel/First%26LastRows.xlsm
In your 2nd piece of code add + 1 to
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
So you have
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row + 1
The former gives you row 2, which is your header row. What you want is row 3, the row right after your headers.
Update: To Show How To Test in Future
Although the .Select method is typically frowned upon. It can be great for testing / debugging. I ran
wsTNO.Range("O" & fstcell & ":S" & lastrow).Select
in the immediate window after I set lastrow and fstcell to find the range that was set. Therefore I knew you didn't want to copy your headers. From there you can figure out what is driving that range to be set and adjust accordingly.

Resources