How to use Range with Variable in VBA [duplicate] - excel

I want to select the formatted range of an Excel sheet.
To define the last and first row I use the following functions:
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
In the next step I want to select this area:
Formula should look like this:
Range(cells(1, 1), cells(lastRow, lastColumn).Select
However, this is not working. Maybe somebody has an idea what is wrong with it. Thanks a lot!

I recorded a macro with 'Relative References' and this is what I got :
Range("F10").Select
ActiveCell.Offset(0, 3).Range("A1:D11").Select
Heres what I thought : If the range selection is in quotes, VBA really wants a STRING and interprets the cells out of it so tried the following:
Dim MyRange as String
MyRange = "A1:D11"
Range(MyRange).Select
And it worked :) ie.. just create a string using your variables, make sure to dimension it as a STRING variables and Excel will read right off of it ;)
Following tested and found working :
Sub Macro04()
Dim Copyrange As String
Startrow = 1
Lastrow = 11
Copyrange = "A" & Startrow & ":D" & Lastrow
Range(Copyrange).Select
End Sub

I ran into something similar - I wanted to create a range based on some variables. Using the Worksheet.Cells did not work directly since I think the cell's values were passed to Range.
This did work though:
Range(Cells(1, 1).Address(), Cells(lastRow, lastColumn).Address()).Select
That took care of converting the cell's numerical location to what Range expects, which is the A1 format.

If you just want to select the used range, use
ActiveSheet.UsedRange.Select
If you want to select from A1 to the end of the used range, you can use the SpecialCells method like this
With ActiveSheet
.Range(.Cells(1, 1), .Cells.SpecialCells(xlCellTypeLastCell)).Select
End With
Sometimes Excel gets confused on what is the last cell. It's never a smaller range than the actual used range, but it can be bigger if some cells were deleted. To avoid that, you can use Find and the asterisk wildcard to find the real last cell.
Dim rLastCell As Range
With Sheet1
Set rLastCell = .Cells.Find("*", .Cells(1, 1), xlValues, xlPart, , xlPrevious)
.Range(.Cells(1, 1), rLastCell).Select
End With
Finally, make sure you're only selecting if you really need to. Most of what you need to do in Excel VBA you can do directly to the Range rather than selecting it first. Instead of
.Range(.Cells(1, 1), rLastCell).Select
Selection.Font.Bold = True
You can
.Range(.Cells(1,1), rLastCells).Font.Bold = True

You're missing a close parenthesis, I.E. you aren't closing Range().
Try this Range(cells(1, 1), cells(lastRow, lastColumn)).Select
But you should really look at the other answer from Dick Kusleika for possible alternatives that may serve you better. Specifically, ActiveSheet.UsedRange.Select which has the same end result as your code.

you are turning them into an address but Cells(#,#) uses integer inputs not address inputs so just use lastRow = ActiveSheet.UsedRange.Rows.count and lastColumn = ActiveSheet.UsedRange.Columns.Count

I tried using:
Range(cells(1, 1), cells(lastRow, lastColumn)).Select
where lastRow and lastColumn are integers, but received run-time error 1004. I'm using an older VB (6.5).
What did work was to use the following:
Range(Chr(64 + firstColumn) & firstRow & ":" & Chr(64 + lastColumn) & firstColumn).Select.

Related

Excel macro - Selecting cell range with a using number from loop [duplicate]

I want to select the formatted range of an Excel sheet.
To define the last and first row I use the following functions:
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
In the next step I want to select this area:
Formula should look like this:
Range(cells(1, 1), cells(lastRow, lastColumn).Select
However, this is not working. Maybe somebody has an idea what is wrong with it. Thanks a lot!
I recorded a macro with 'Relative References' and this is what I got :
Range("F10").Select
ActiveCell.Offset(0, 3).Range("A1:D11").Select
Heres what I thought : If the range selection is in quotes, VBA really wants a STRING and interprets the cells out of it so tried the following:
Dim MyRange as String
MyRange = "A1:D11"
Range(MyRange).Select
And it worked :) ie.. just create a string using your variables, make sure to dimension it as a STRING variables and Excel will read right off of it ;)
Following tested and found working :
Sub Macro04()
Dim Copyrange As String
Startrow = 1
Lastrow = 11
Copyrange = "A" & Startrow & ":D" & Lastrow
Range(Copyrange).Select
End Sub
I ran into something similar - I wanted to create a range based on some variables. Using the Worksheet.Cells did not work directly since I think the cell's values were passed to Range.
This did work though:
Range(Cells(1, 1).Address(), Cells(lastRow, lastColumn).Address()).Select
That took care of converting the cell's numerical location to what Range expects, which is the A1 format.
If you just want to select the used range, use
ActiveSheet.UsedRange.Select
If you want to select from A1 to the end of the used range, you can use the SpecialCells method like this
With ActiveSheet
.Range(.Cells(1, 1), .Cells.SpecialCells(xlCellTypeLastCell)).Select
End With
Sometimes Excel gets confused on what is the last cell. It's never a smaller range than the actual used range, but it can be bigger if some cells were deleted. To avoid that, you can use Find and the asterisk wildcard to find the real last cell.
Dim rLastCell As Range
With Sheet1
Set rLastCell = .Cells.Find("*", .Cells(1, 1), xlValues, xlPart, , xlPrevious)
.Range(.Cells(1, 1), rLastCell).Select
End With
Finally, make sure you're only selecting if you really need to. Most of what you need to do in Excel VBA you can do directly to the Range rather than selecting it first. Instead of
.Range(.Cells(1, 1), rLastCell).Select
Selection.Font.Bold = True
You can
.Range(.Cells(1,1), rLastCells).Font.Bold = True
You're missing a close parenthesis, I.E. you aren't closing Range().
Try this Range(cells(1, 1), cells(lastRow, lastColumn)).Select
But you should really look at the other answer from Dick Kusleika for possible alternatives that may serve you better. Specifically, ActiveSheet.UsedRange.Select which has the same end result as your code.
you are turning them into an address but Cells(#,#) uses integer inputs not address inputs so just use lastRow = ActiveSheet.UsedRange.Rows.count and lastColumn = ActiveSheet.UsedRange.Columns.Count
I tried using:
Range(cells(1, 1), cells(lastRow, lastColumn)).Select
where lastRow and lastColumn are integers, but received run-time error 1004. I'm using an older VB (6.5).
What did work was to use the following:
Range(Chr(64 + firstColumn) & firstRow & ":" & Chr(64 + lastColumn) & firstColumn).Select.

2 Problems with a VBA Macro and Date Formating

I have looked at other posts but cannot find anything that is similar enough to my problems. Any help will be appreciated.
I have a set of dates that come in everyday; the dates come in the following format: DD.MM.YYYY (I live in a country that has the day first). I need the data to change into DD/MM/YYYY. I then use these dates in a Vlookup as part of the data set that holds the information I wish to retrieve.
I need help with the following problems:
Problem # 1
When I use the macro and switch the "." with the "/", days 1 to 12 have been switched to the following format DD/MM/YYYY. However, the actual month and day have switched. Currently working in April so 01.04.2020 has been switched to 04/01/2020 (Reading as January fourth); 04/02/2020 (February second and so on....). How can I prevent this from happening so that everything stays in place and just the "." and the "/" change.
Problem #2
From day 13 and onwards the format looks right “13/04/2020”, however when I use it in the Vlookup, the formula will not bring any results back. In order for the Vlookup to work, I have to go to the cell that I just changed and press delete in front of the first digit, even though there is no space there; in order for the Vlookup to work.
Why does that happen? What can I do it so it work right after replacing the “.” and the “/”
Below is my code
Sub Dates()
Range(Range("G12"), Range("G12").End(xlDown)).Select
Selection.NumberFormat = "dd.mm.yyy"
Selection.Replace What:=".", Replacement:="/", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.NumberFormat = "dd/mm/yyy"
End Sub
Try,
Sub test()
Dim vDB, rngDB As Range
Dim s As Variant
Dim i As Long
Set rngDB = Range("G12", Range("G12").End(xlDown))
vDB = rngDB
For i = 1 To UBound(vDB, 1)
s = Split(vDB(i, 1), ".")
vDB(i, 1) = DateSerial(s(2), s(1), s(0))
Next i
rngDB = vDB
rngDB.NumberFormatLocal = "dd/mm/yyyy"
End Sub
Error Image
Correct Image
Here is a solution for your code as is.
I strongly recommend reading and further understanding How to avoid Select in Excel VBA to improve your code and reduce risk of runtime errors.
If you add this code to the bottom of your existing procedure (as it is shown in your question) it will loop through each cell and re-format it to the correct date value.
Dim myCell As Variant
Dim myRange As Range
Set myRange = Selection
For Each myCell In myRange
myCell.Value = Format(CDate(myCell), "DD/MM/YYYY")
Next
You might find this link helpful also:
Better way to find last used row
If you refine your code taking into account the information in both links, you will end up avoiding .Select and Selection. entirely, and your target range/cell will be less ambiguous.
I'd reformat it as follows:
Note: I have written this on Sheet1 of a new workbook, you would need to change the Sheets("...") reference to match your sheet name.
Sub dates()
Dim myRange As Range
Dim LastRow As Long
Dim myCell As Range
With ThisWorkbook.Sheets("Sheet1")
LastRow = .Cells(.Rows.Count, 7).End(xlUp).Row
Set myRange = Range("G12:G" & LastRow)
For Each myCell In myRange
myCell.Value = Replace(myCell, ".", "/")
myCell.Value = Format(CDate(myCell), "DD/MM/YYYY")
Next myCell
End With
End Sub
Now it's a lot clearer where on our workbook we are making changes which helps improve readability for yourself and others (such as other users on SO) along with reduces ambiguity and risk of RunTime errors.
Thanks for the text to column advise this is what I did for it to work:
Sub Dates ()
Dim rg As Range
Set rg = Range("G12").CurrentRegion
rg.TextToColumns Destination:=Range("H2"), ConsecutiveDelimiter:=True, DataType:=xlDelimited, Other:=True, OtherChar:="."
lr = ActiveSheet.Cells(Rows.Count, "G").End(xlUp).Row
Range("K2").Formula = "=DATE(J2,I2,H2)"
Range("K2").AutoFill Range("K2:K" & lr)

vba copy and paste range value when two or more conditions are satisfied into the next empty cell

I'm very new to VBA and was hoping to get come clarification on a project. I've tried solving it with formulas but I need to still be able to enter information into cells and not have them filled with a lookup formula.
How I'm looking for it to preform is that if an object requires it to be shipped then the serial numbers and identifiers are copied and pasted in another table in the next blank row automatically.
Information divided into two tables
What I thought I needed was a segment in VBA that went like this:
Sub CopyCat()
If Range("J2") Like "*yes*" then
Range("G2:I2").copy
Range("A2:A10").end(xlup).offset(1).pasteSpecial xlpastevalues
If Range("J3") Like "*yes*" then
Range("G3:I3").copy
Range("A2:A10").end(xlup).offset(1).pasteSpecial xlpastevalues
End If
End If
End Sub
It does exactly what I ask it to do when it is only the first statement, when I add the second one to check if the next row satisfies the conditions and it does, then it places it in the same resulting cell as the first statement. If both are true I need them both to be displayed in table 1.
I'd love to take this as a learning opportunity so any information or direction you can point me in would be great! Thank you so much in advance!
I think Range("A2:A10").end(xlup) is equivalent to Range("A2").end(xlup) so will not change, but you don't want the A2 reference, you want to work up from the bottom. You will hit problems if you are going beyond A9. (Plus not sure you want nested Ifs.)
If Range("J2") Like "*yes*" Then
Range("G2:I2").Copy
Range("A10").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
If Range("J3") Like "*yes*" Then
Range("G3:I3").Copy
Range("A10").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
Or to add a loop and circumvent the copy/paste you could use something like this:
Sub CopyCat()
Dim r As Long
For r = 2 To Range("J" & Rows.Count).End(xlUp).Row
If Range("J" & r) Like "*yes*" Then
Range("A10").End(xlUp).Offset(1).Resize(, 3).Value = Range("G" & r).Resize(, 3).Value
End If
Next r
End Sub
You can also do this without VBA.
In A2, you can use this formula entered as an array formula with CTRL+SHIFT+ENTER:
=INDEX($G$2:$G$4,SMALL(IF($J$2:$J$4="yes",ROW($J$2:$J$4)-ROW($J$2)+1),ROWS(J$2:J2)))
And in B2, you can put this and drag down/over from B2:D3:
=INDEX(H$2:H$4,MATCH($A2,$G$2:$G$4,0))
Finally, to hide the errors that show when there are no more matches, you can simply wrap both above formulas in IFERROR([formula above],"").
With autofilter
Sub copyRange()
Dim wb As Workbook
Dim wsSource As Worksheet
Dim lastRow As Long
Dim filterRange As Range
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Sheet2") 'change to sheet name containing delivery info
With wsSource
lastRow = .Cells(.Rows.Count, "G").End(xlUp).Row
Set filterRange = .Range("G1:K" & lastRow)
Dim copyRange As Range
Set copyRange = .Range("G2:K" & lastRow)
End With
Dim lastRowTarget As Long, nextTargetRow As Long
With filterRange
.AutoFilter
.AutoFilter Field:=4, Criteria1:="yes" 'change field to whichever is the field in the range containing your company names
lastRowTarget = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).Row
nextRowTarget = lastRowTarget + 1
Union(wsSource.Range("G2:I" & lastRow).SpecialCells(xlCellTypeVisible), wsSource.Range("K2:K" & lastRow).SpecialCells(xlCellTypeVisible)).Copy wsSource.Range("A" & nextRowTarget)
.AutoFilter
End With
End Sub

Trouble with an Excel VBScript, Referencing A Relational Cell Address

Okay, I'm learning scripting for Excel and I've come across something that I just don't know how to do.
I've been asked to help automate the import of a sheet into a sheet and then add some columns off to the side and do some calculations and autofill them to the last row of the imported info. That is no problem. I recently found out however that the sheet that I would import for my office has X number of columns and other offices have Y and Z number of columns in the sheets that they would import. So I'm trying to do this to where it builds the calculation columns at the end of the imported columns. With that bit of background here's where I need some assistance:
Script as written for my office and works:
Range("O1").Select
ActiveCell.FormulaR1C1 = "Remainder"
Range("O2").Select
ActiveCell.FormulaR1C1 = "=MOD(RC[-14],RC[-5])"
Range("O2").Select
Range("O2").AutoFill Destination:=Range("O2:O" & Cells(Rows.Count, "B").End(xlUp).Row)
So now I need to make this relational not Cell Address Specific So I came up with this.
Range("A1").select
Selection.End(xlToRight).Select
ActiveCell.Offset(0, 1).Select
ActiveCell.FormulaR1C1 = "Threshold"
ActiveCell.Offset(1, 0).Select
ActiveCell.FormulaR1C1 = "=IF(RC[-13]>(RC[-5]/3),""Over"",""Under"")"
Range(ActiveCell.Address).AutoFill Destination:=Range(*****How to return the Current Cell Address** : **How to Return the Current Column Letter***** & Cells(Rows.Count, "B").End(xlUp).Row)
I've Tried "ActiveCell.Address":"CHAR(COLUMN()+64))" but That doesn't work and I Just don't know how to get it to set that value to Be the equivalent ?2:? my office running this should autofill from O2:O. But would return P2:P in another.
I'm assuming you want the formula to go in the 1st unused column, no matter how many columns there are. (This will allow for future column use, as well.)
Dim LastCol as integer
LastCol = Cells(1, Columns.Count).End(xlToLeft).Column + 1
Cells(1, LastCol).FormulaR1C1 = "Remainder"
Cells(2, LastCol).FormulaR1C1 = "=MOD(RC[-14],RC[-5])"
Cells(2, LastCol).AutoFill Destination:=Range(Cells(2, LastCol), _
Cells(Cells(Rows.Count, "B").End(xlUp).Row, LastCol))
How's this:
Sub test()
Dim lastCol As Integer, lastRow As Integer, formulaCol As Integer
Dim ws As Worksheet
Set ws = ActiveSheet
' First, let's find the last column (#) and last row (#)
With ws.UsedRange
lastCol = .Columns.Count
lastRow = .Rows.Count
End With
' Now, create the "header, two columns offset from last column"
formulaCol = lastCol + 2
Cells(1, formulaCol).Value = "Remainder"
'Now, let's create a range, that we will fill with the MOD() formula. You can do this _
through resizing a range, instead of selecting and autofill
With ws
.Range(.Cells(2, formulaCol), .Cells(2, formulaCol)).Resize(lastRow - 1, 1).FormulaR1C1 = _
"=IF(RC[-" & formulaCol - 1 & "]>(RC[-2]/3),""Over"",""Under"")"
End With
End Sub
I am assuming a few things: Your raw sheets come with the data in one block. In other words, you don't have a gap of columns between data you need. This will get the last used column and row, and use those to enter your formula.
Also, I assume that you are checking that the first part of your mod() formula refers to the info in Col. A, and the second part is the right most column's data. I think I'm not understanding something, so any more info. about how the data is laid out would be helpful. But also, this avoids using "Select", which is good VBA practice from what I've gathered.

Range to cells with xldown

hey I have this part of code
Range("A2:BY2").Select
Range(Selection, Selection.End(xlDown)).Select
I want to convert into Cells to have my code quicker
I tried this
With Worksheets("BLOTTER")
Set rng = .Range(.Cells(1, 2), .Cells(77, 2).End(xlDown))
End With
but doesnt seems to select the good range
Thank you
Not sure if this will help becuase I'm not sure I remember the end properly, but it doesn't appear you are using the right syntax with your set rng statement... try this:
Set rng = .Range(.Cells(1, 2).Address & ":" & .Cells(77, 2).End(xlDown).Address)
If I'm remembering properly, the range needs to be set as a string, or at least I always did it that way, and the .Address property returns the string name of the cell you referenced, e.g. .Cells(1, 2).Address returns "$A$2".
This will select the range you want, but using .Select should be avoided. Why do you want to select this range? A copy/paste? Formatting? You don't need to select the range for any of those operations.
Sub getRange()
Dim rng As Range
Set rng = Range("A2:BY2")
rng.Select
End Sub

Resources