I have spent the day trying to understand what is going on with my excel.. I am running some code which worked fine before, I modified part of it early up (but which still works fine), and now a Selection.Copy later on in the code has stopped working. Here it is :
Range("AE3").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
I used break points to find the problem. After the first two lines of code, it is the data in column AE which is selected. When I move on to the last line (Selection.Copy), it is not the data in AE which is selected but the columns AA and AB. I have tried literally everything I can think of to try and fix this but can't find anything..
If I run the code up to this point of the code and do the selection and copying manually, it also copies the wrong cells (it copies AA and AB like when it's done with vba)
I would post screenshots of it but you can't put photos here it seems.
Thanks for your help!
Resolved:
I went through the code step by step and noticed that previously in the code I copied the data from columns AA and AB to lower columns. To do so I had selected the columns and then copied them. I changed that so that I selected only the data in the columns and not the columns themselves and copied the data. This change has made my code work. I'm not sure why this was effecting the later Selection.Copy, but it was in some way. Thank you everyone for their help!
As I've suggested in my comment, avoid using .Select & Selection, is usually bad practice and almost everything can be done in VBA without the need to use them. I understand those are a result of the recorder (which is a good place to start learning how to do certain things in VBA), just need to learn as well how to use the code generated by the recorder.
See if this helps (see comments in code as well):
Sub copyRange()
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1") 'use a variable for the sheet you want to use
Dim lRow As Long
lRow = ws.Cells(Rows.Count, "AE").End(xlUp).Row 'get the last row at the desired column
With ws
.Range("AE3:AE" & lRow).Copy _
Destination:=.Range("AE3:AE" & lRow).Offset(0, -10) 'destination offset 10 columns to the left
'or alternatively specify the destination
'Destination:=.Range("U3:U" & lRow)
End With
'ALTERNATIVE to the above - copy values only
With ws.Range("AE3:AE" & lRow)
.Offset(0, -10).Value = .Value 'destination offset 10 columns to the left
'or alternatively specify the destination
'ws.Range("U3:U" & lRow).Value = .Value
End With
'2nd ALTERNATIVE to the above - copy values only
With ws.Range(ws.Cells(3, 31), ws.Cells(lRow, 31))
.Offset(0, -10).Value = .Value 'destination offset 10 columns to the left
'or alternatively specify the destination
ws.Range(ws.Cells(3, 21), ws.Cells(lRow, 21)).Value = .Value
End With
End Sub
Note the use of With statement, .Range(...) is not the same as Range(...).
In case you want to copy all in column AE try this:
Range("EA3:EA" & Range("EA" & Rows.Count).End(xlUp).Row)).Copy
And to paste you could use:
Range("U3").PasteSpecial (xlPasteValues)
Also, I strongly suggest you to read:
How to avoid using Select in Excel VBA
You could try:
Option Explicit
Sub test()
Dim LastRow As Long
'Create a with statement refer to the sheet where your data are
With ThisWorkbook.Worksheets("Sheet1")
'Find the LastRow of column AE
LastRow = .Cells(.Rows.Count, "AE").End(xlUp).Row
'Refer to the range starting from AE3 and ends at Lastrow
.Range("AE3" & ":AE" & LastRow).Copy
End With
End Sub
Results:
Related
The intent is to:
On Sheet(Master), update a Cell which triggers other cells to update a specific range.
On Sheet(Master), select updated range and copy that range.
On Sheet(Paste), paste the values and formatting of the copied data below the last row of data.
The script below functions properly, except for the paste special portion: PasteSpecial Paste:=xlPasteValues.
Private Sub CommandButton1_Click()
'/ I am trying to Add Data From Sheet("Master") To Sheet("Paste") as a "PasteSpecial Paste:=xlPasteValues"
Dim Lastrow As Long
Sheets("Master").Range("N3") = Sheets("Master").Range("N3") - Sheets("Master").Range("N4")
Lastrow = Sheets("Paste").Range("A65536").End(xlUp).Row + 1
Sheets("Master").Range("L13:AO17").Copy Destination:=Sheets("Paste").Range("A" & Lastrow)
End Sub
I have attempted to add the PasteSpecial Paste:=xlPasteValues portion as in the examples below:
Example One.
Lastrow = Sheets("Paste").Range("A65536").End(xlUp).Row.PasteSpecial Paste:=xlPasteValues
Example Two.
Sheets("Master").Range("L13:AO17").Copy Destination:=Sheets("Paste").Range("A" & Lastrow).PasteSpecial Paste:=xlPasteValues
Those are the only two types of options that I have attempted based on online research.
After reworking it a few times, the following solution worked.
Range("N3") = Range("N3") - Range("N4")
Range("L13:AO17").Copy
Sheets("Paste").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
I decided to step away from using the Lastrow var, when I realized that it was not needed. Once that was eliminated, I then focused on cleaning the script and used the offset function instead of row. This then allowed for me to add the PasteSpecial function properly.
I have a a sheet of data, and I want to filter based on the start of the policy number, and then I want to move all of the BFL policies after PFL policies. Row 1 contain all of the headers. My policy number starts with either PFL or BFL.
The reason why I can't sort Z-A directly because the raw data starts with BFL001 to BFL999 then PFL001 to PFL999 so sorting Z-A will get PFL999 first, but I want to just move everything from BFL001 to BFL999 after PFL001, like simple cut and paste. My range varies each month so I am using 001 to 999 to show you how my raw data is displayed.
After I run my current VBA module, it starts from row 1000 and from BFL001 to PFL999 which is not what I want. I need to start from PFL001 to PFL999 and then BFL001 to BFL999, and with no blank rows in between.
I am not sure if I can use partial search or use text like to find policies that starts with BFL then cut and paste to last row + 1. Not sure which way is faster.
Sub test()
Dim LR1 As Long
LR1 = Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
.Cut Range("A" & LR1 + 1)
End With
.AutoFilterMode = False
End With
End Sub
A neat trick with VBA is that you can reference certain cells that share a property using .SpecialCells in your case you'd want to use xlCellTypeVisible but there are many others that can be used.
The trick here is to do the cut manually. You can't cut cells that aren't right next to each other, but you can copy and paste them. So the idea is to paste the BFL cells below the PFL cells and then empty out the original cells and clean up the white spaces. After you apply the autofilter you can tell excel to only look at the visible cells within the same range that you specified before, so you don't get anything extra. This is important because when you go to clear all the visible cells, you don't want to accidentally clear the cells you just pasted below.
When you're cleaning up blank cells it's important to go from the bottom up because other wise you could run into indexing issues. You'll also notice that I use .entirerow so that it deletes the entire row instead of just the first column.
To show all of the data you simply go Worksheet.showalldata, BUT you need to check if there is even an autofilter applied to the sheet. Occasionally when you perform operations such as clearing cells, it'll turn off the autofilter, so it's best to check whether its still there or not so your macro doesn't throw an error at you.
One last tiny thing, although you're not wrong, it's not necessary to concatenate a string with the wildcard * you could simply have them within the same string. eg. "BFL*" vs "BFL" & "*" just saves a bit of time on typing.
Sub test()
Dim LR1 As Long
Dim BFLRange As Range
LR1 = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
Set BFLRange = .SpecialCells(xlCellTypeVisible)
BFLRange.Copy Destination:=Worksheets("Combined").Range("A" & LR1 + 1)
End With
BFLRange.Clear
For i = LR1 To 2 Step -1
If IsEmpty(.Cells(i, 1)) Then
.Cells(i, 1).EntireRow.Delete shift:=xlUp
End If
Next i
If .AutoFilterMode Then
.ShowAllData
End If
End With
End Sub
This snippet follows #SJR's suggestion where you delete the entire used region containing BFL. The reason I've disabled alerts is because there's just a little text box that pops up asking if you're sure you want to delete the sheet rows. By turning it off, it doesn't require any user input. It's good to note that by deleting the cells at once, it'll speed up the macro drastically if you're working with a large amount of data. Thanks again #SJR.
Sub test()
Dim LR1 As Long
Dim BFLRange As Range
LR1 = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
Set BFLRange = .SpecialCells(xlCellTypeVisible)
BFLRange.Copy Destination:=Worksheets("Combined").Range("A" & LR1 + 1)
End With
Application.DisplayAlerts = False
BFLRange.Delete
Application.DisplayAlerts = True
' For i = LR1 To 2 Step -1
' If IsEmpty(.Cells(i, 1)) Then
' .Cells(i, 1).EntireRow.Delete shift:=xlUp
' End If
' Next i
If .AutoFilterMode Then
.ShowAllData
End If
End With
End Sub
I recorded a macro, it filters a sheet, copies the filtered data and pastes it into another workbook. It worked the first few times I used it, now it gives me an error:
Run-time 1004 - We can't Paste because the Copy area and Paste area
aren't the same size.
Nothing changed, it just now flags the error on the "ActiveSheet.Paste" line. Can anyone explain why it does this out of nowhere randomly? I know tomorrow when I try again it will work fine for a few uses then do this again. I looked online it seems to be a common issue, I haven't found a solution that has worked for me yet, does anyone have an idea? Or is there another way to do this maybe so I can just avoid it?
The code:
Sub Macro201()
ActiveSheet.Range("$A$6:$H$55").AutoFilter Field:=8, Criteria1:="99"
Range("A7:B7").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Windows("invoiceTEST.xls").Activate
Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveSheet.Paste
Range("C" & Rows.Count).End(xlUp).Offset(1).Select
End Sub
First of all, you don't need to select anything. For example, Range("A7:B7") is a range. Selection is also a range (in this context). So, you assign the range to a Selection.Range and then use the Selection.Range. Why not use the Range you defined at the outset?
Next, you do have to specify the Worksheet you are working on, especially the one in the target workbook.
Finally, you must clearly identify the last rows you use. Your formula picks the last row in the sheets you work with, not the last used row. So you are throwing around millions of blank cells.
Put all of the above together and you arrive a code like the following.
Sub CopyData()
' 01 May 2017
Dim Rng As Range
With ActiveSheet
Set Rng = .Range("$A$6:$H$55")
Rng.AutoFilter Field:=8, Criteria1:="99"
If Application.WorksheetFunction.Subtotal(3, Rng) = 0 Then Exit Sub
.Range("A7:B" & .Cells(.Rows.Count, "A").End(xlUp).Row).Copy
End With
With Workbooks("invoiceTEST.xls").Sheets(1)
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial
End With
End Sub
Note that the code will fail if the target workbook isn't open when you attempt to run it.
Using MS-Excel 2007, I noticed that in this code, I noticed that when run the first row of the target is always empty. Why is that? Thanks.
Instead of
Range("A65536").End(xlUp).Offset(1, 0).PasteSpecial
you can use something like that
Dim LastUsedCell As Range
Set LastUsedCell = Range("A" & Rows.Count).End(xlUp)
If IsEmpty(LastUsedCell) Then
LastUsedCell.PasteSpecial
Else
LastUsedCell.Offset(1, 0).PasteSpecial
End If
to start with row 1 on an empty sheet.
Please consider this option.
https://www.rondebruin.nl/win/addins/rdbmerge.htm
Post back if you have additional questions.
I have a membership roster that I am keeping for a chapter in a club. Rather than delete members who are no longer in the chapter, I decided to try and create a macro that looks at the Chapter Roster Master sheet in column A (Still in Chapter?) for a "yes" value and then transfers the all the rows with the yes value to another sheet called "Chapter Roster Actual".
The macro works but I would like to only transfer columns B through O and not include Column A.
I realize the one line actually tells the macro to copy the "entire row" and I have tried to have it copy only a range but in doing that, it disregards the request to only copy rows where column A has a 'yes' value. I have the range line in there as well so you could see what I tried.
I also need to figure out how to not append the rows to previously copied rows. So, I guess it should clear the rows previously populated and then write the new rows.
Here is the macro:
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
For myRow = 3 To LastRow
If Sheets(myworksheet).Cells(myRow, "A").Value = "Yes" Then
Sheets(myworksheet).Cells(myRow, "A").EntireRow.Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
'Sheets(myworksheet).Range("B3:O32").Copy Destination:=Sheets("Chapter Roster Actual").Range("A3:O32").End(xlUp).Offset(1)*
End If
Next myRow
End Sub
In what you tried, you are copying all the rows starting from 3 right upto 32 even if only current row is 'Yes'
The following works fine
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
Sheets("Chapter Roster Actual").Range("A3").CurrentRegion.Offset(2,0).ClearContents
Sheets(myworksheet).Activate
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
For myRow = 3 To LastRow
If Sheets(myworksheet).Cells(myRow, "A").Value = "Yes" Then
Sheets(myworksheet).Range(Cells(myRow,"B"),Cells(myRow,"O")).Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
End If
Next myRow
End Sub
As suggested in a comment, you can also try filter the Master data and copy all required data in one shot. As a starting point, record a macro and you will get a feel of how that can be done. Come back to refine recorded code.
You can use below code If you want to try using the filter instead of iterating over all the records. You can check which works best for you and use.
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
Range("A2").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.AutoFilter
Range("A2").Select
ActiveSheet.Range("A2", Range("A2").End(xlToRight)).AutoFilter Field:=1, Criteria1:="Yes"
Range("A2").End(xlToLeft).Select
ActiveCell.Offset(1, 0).Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
End Sub
Note: There might be more optimized code for this scenario too
Tip: You can learn how macro works by opening the VBA along with Excel (in side by side mode), record the macro and observe the code generated.