VBA how to change a range variable using something like offset - excel

I'd think that the following code should produce a diagonal of numbers, and I am wondering why this code doesn't work as intended:
Sub RangeExample()
Dim a As Range
Set a = Sheets(1).Range("a1")
a.Value = 0
Dim i As Integer
For i = 1 To 100
a = a.Offset(1, 1)
a.Value = i
Next i
End Sub
I understand there are many ways of producing a diagonal of numbers, I'm not asking how to do that.
What I'm asking is how I would change my range variable a to become a different range, and do that iteratively. It seems to me that as a.offset(1,1) returns a range object that's one over and one down, I should be able to reassign a as this new range, assign a value, and move on.

Your current issue is that you're missing a Set:
Set a = a.Offset(1, 1)
Note that you could also just use i and not reSet:
a.Offset(i, i).Value = i
Another option is to use Cells, e.g.
Sheets(1).Cells(i + 1, i + 1).Value = i
There's more than one way to skin a cat - pick whatever is easiest and most intuitive to future you.

Thanks for the answer, I didn't know set was required in this case. The specific answer I was looking for I have now found at:
What does the keyword Set actually do in VBA?
Specifically, the following answer by LeppyR64. "Set is used for setting object references, as opposed to assigning a value."
I didn't know that equality alone only impacted the value of the range object a. To actually change the range a was referencing, I needed set because a is supposed to refer to a new range object.

the issue has already been addressed by #BigBen
but you could avoid re-setting the range at every iteration by means of With...End With block
Option Explicit
Sub RangeExample()
Dim i As Long
With Sheets(1).Range("a1") ' reference topleftmost cell
.Value = 0 ' write referenced cell value
For i = 1 To 100
.Offset(i, i).Value = i 'write referenced cell current offset value
Next
End With
End Sub

Related

Object Required or Object variable or With Block errors

I am trying to use VBA to combine data from several different look up ranges for an SQL script writer. At this stage I am trying to identify whether the value I am looking up has an adjacent cell with a specific value. I have tried several iterations. My most recent is the following:
Dim r As String
With Worksheets(12).Range("q2:R80")
r = Cells(.Find(u(0, 1).Row, 18)).Value
End With
I have tried with and without the "With" statement as well as with and without "." before the methods and properties and with and with out the ".Value" and no matter what combination I use, I get an object error of some kind or another. I know I am missing something obvious, but Google has been of no help.
Your parentheses look off:
With Worksheets(12).Range("q2:R80")
r = Cells(.Find(u(0, 1).Row, 18)).Value
End With
seems like it should be:
With Worksheets(12).Range("q2:R80")
r = Cells(.Find(u(0, 1)).Row, 18).Value
End With
But this is still problematic, becauses it assumes the Find succeeded by chaining the .Row call.
Better practice is the following:
With Worksheets(12).Range("q2:R80")
Dim foundRng as Range
Set foundRng = .Find(u(0,1)) '<~ you really should specify the other parameters of Range.Find
If Not foundRng Is Nothing Then
r = Cells(foundRng.Row, 18).Value '<~ make sure to qualify the worksheet the Cells are on
End If
End With

Offsetting a range that is found manually

I have a situation where I am using these equations
=CELL("address",INDEX(J61:W61,MATCH(LARGE((J61:W61),1),J61:W61,0)))
To find the cell address of the largest value cell in that range.
For example, it gives me this as a result. $T$61 (which contains the highest value).
I now want to use that information and offset it upwards 51 rows to extract the title for this column. How can I use this information and a formula, or VBA to find the content of $T$10 in this case?
Obtaining the cell address in this case is not necessary. What's more, CELL is a volatile function, and so should be avoided if possible.
Simply:
=INDEX(J10:W10,MATCH(MAX(J61:W61),J61:W61,0))
Regards
I ended up finding a way to use vba to do what I need
Sub Top_3_Problems()
First_Address = Range("D62")
Second_Address = Range("D63")
Third_Address = Range("D64")
First_problem = Range(First_Address).Offset(-51)
Second_problem = Range(Second_Address).Offset(-51)
Third_problem = Range(Third_Address).Offset(-51)
Range("B40") = First_problem
Range("B41") = Second_problem
Range("B42") = Third_problem
End Sub
Quick example of how to do this in VBA
This is just a simple example. If implemented, objects need to be properly qualifed with a worksheet and the Find method needs to have options added
Option Explicit
Sub MaxHeader()
Dim Found As Range, SearchRange As Range
Set SearchRange = Range("J61:W61")
Set Found = SearchRange.Find(WorksheetFunction.Max(SearchRange))
If Not Found Is Nothing Then MsgBox Cells(10, Found.Column)
End Sub

Using a variable for a range

I am writing a macro and am having issues with using a range variable. I think I am setting the range properly, but I cannot do anything with the range. Pseudocode below:
Dim rng As Range
Set rng = Report(1) 'A function which will be defined below
trackWkbk.Sheets(strFY).rng = 10 <--'THIS IS WHERE I am getting the error.
'trackWbkb is a workbook that is defined properly; I use it elsewhere with no errors.
'strFY is defined and working properly, I use it to call sheets in trackWbkb elsewhere with no errors.
The sub function code is:
Function Report(a) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = Range("B2")
End Select
End Select
End Function
I know my select case statements are gonna get pretty convoluted (this is just a testing sample), but I don't think the issue is there.
Let me know if I should include more code. My code compiles. I think this is something simple that I am missing, but I have been looking online for the past half hour and can't seem to find anything that will resolve this. Does anyone know how to resolve this? Thanks
Your function already returns a Range object. It's not clear to me whether you're trying to obtain a range on another worksheet that is at the same address as a range on the active worksheet. However, you could directly obtain the desired range if you passed the worksheet reference to your function:
Function Report(ByVal poParentWorksheet As Excel.Worksheet, ByVal a As Integer) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = poParentWorksheet.Range("B2")
End Select
End Select
End Function
Then you could use:
Set rng = Report(trackWkbk.Sheets(strFY), 1)
rng.Value = 10
When you set a range variable you are creating a pointer in memory to a specific range in a specific sheet. It's not storing a cell address, so you can't write
trackWkbk.Sheets(strFY).rng
Either adopt Excelosaurus's solution, or change your function to return a cell address as a string and then use
trackWkbk.Sheets(strFY).range(rng)

Excel vba for each loop with if statement and structured references

I want to change the value in a column of a table based on the value of another column in the same table using structured references. So far I have something like:
Sub Test
For Each cell In Worksheets("FNM_DB").Range("DB_SS[Resource_Loc_Type]")
If cell.Value = "TH" Then
Worksheets("FNM_DB").Range("DB_SS[Resource]") = Worksheets("FNM_DB").Range("DB_SS[SOURCE_AND_SINK_NAMES]")
End If
Next cell
End Sub
I know I could do this without the structured reference, but I want the code to be more readable. Is there a way to loop through all the values? I know the # refers to a specific row, but I don't know how to use it in this instance.
The above statement
The # sign refers to the current row, but that syntax only works inside a worksheet cell, not within a VBA.
is false.
This works:
[tblActualsWithFacts[#1c]].Select
these work too:
Range("tblActualsWithFacts[#1c]").Select
For i = 1 to 12
Range("tblActualsWithFacts[" & i & " c]").Select
Next i
however, the combination of the above techniques i.e. concatenating a structured reference which makes use of "#" does not work, therefore this does NOT work
For i = 1 to 12
Range("tblActualsWithFacts[#" & i & " c]").Select
Next i
While it is possible to use structured references in VBA, addressing the current row is different. The # sign refers to the current row, but that syntax only works inside a worksheet cell, not within a VBA.
If you are concerned about readability, I'm not sure the long syntax is helpful at all. My suggestion is to create variables that represent the offset of the table column name from the current column. Something like this:
Sub test()
Dim Height As Integer, Width As Integer, Result As Integer
Result = 3
Height = 1
Width = 2
For Each cel In Worksheets("Sheet1").Range("SizingTable[Colour]")
If cel.Value = "red" Then
cel.Offset(0, Result) = cel.Offset(0, Height) * cel.Offset(0, Width)
End If
Next cel
End Sub

Type mismatch error #13

I have a For loop that iterates through each row, I need to pull the value from the D column for each row to use in the loop.
I was trying to use the following to pull the value by using the value of the counter as the row number.
X = Worksheets("Test").Cells(4, Counter).Value
I keep encountering a Type mismatch error #13
These are the two scenarios I can think of when you will get that error
A You have defined X as a specific data type but are assigning a different type to it. For example. You have defined X as Long but the cell contains a String. Let's say your cell is A1 and it has excelSU. To replicate the error see this example
Sub Sample()
Dim x As Long
x = ThisWorkbook.Sheets("Sheet1").Range("A1").Value
End Sub
Similarly you could have declared Counter of a specific type but using as a different. For example
Sub Sample()
Dim counter As Excel.Application
For counter = 1 To 20
x = ThisWorkbook.Sheets("Sheet1").Range("A" & counter).Value
Next
End Sub
B Let's again take the example of cell A1. Your cell has a formula error like #N/A or #DIV/0! or some other error. To replicate the error use the same code as above and you will get the Type Mismatch Error
EDIT
by using the value of the counter as the row number
BTW, Counter is not being used as a Row but as Column. The syntax is Cells(Row,Column)
You might be pulling strings into a Integer array, or something similar.
As for your for-loop :
I just answered someone's question on a somewhat similar problems.
I suggest going over the fully-functional code example I gave him.
Namely because:
You are using hard-coded values (4rth column). You will eventually run into maintenance problems. A user that adds a column will easily screw up your code.
Your code won't speak for itself. If you replace your hard-coded values with properly named variables, they will.
NOTE: This might be more consuming on the processor due to the number of intersections. You can always adapt your strategy if you ever come up with tables that have over 10,000 rows.
Check the link and answer, but meanwhile here's a short-version of how I'd do it with Tables / ListObjects:
dim listO as ListObject
set listO = Worksheets("Test").ListObjects(1)
dim listC as ListColumn
set listC = ListO.ListColumns("ColumnTitle")
dim listR as ListRow
dim anArrayX() as Variant
ReDim anArrayX (1 to listO.ListRows.Count)
dim intersectedRange as Range
for i = 1 to listO.ListRows.count
set rowRange = ListO.ListRows(i).Range
set intersectedRange = Application.Intersect(rowRange, listC.Range)
anArrayX(i) = intersectedRange.Value
Debug.Print anArrayX(i)
next i

Resources