Excel VBA - Using the range function within a range function - vba

There are 2 things to note here. The first: I am using a For loop to step through each row. The second: I don't know which is the last column with data in each row and hence I am trying to use the Range.End function to find it. To Select the last column with data in row x, the code that works is:
Cells(x, Range("C" & x).End(xlToRight).Column).Select
As you can see from the above, I am starting from column C, row X and looking for the last cell with data in that row. I don't think it matters which column I start from as Column A, B, C, D and E will definitely have data.
Now I try to select a range from Cells(x, 3) (or column C row X) to the above last cell with data in row x. The following code doesn't work:
Range("Cells(x,3):Cells(x, Range("C" & x).End(xlToRight).Column)").Select
I don't know if I am allowed to use the range function like that. The error is a compile error stating "expected: List separator or )" and it highlights the C in Range("C" & x) I looked carefully but don't see anything missing.
I highly appreciate any assistance.

Your method using End(xlToRight) will work only if your range is continous.
If you have blank cells in the middle of the range (let's say columns M and N are empty) you will not get the cells with data in Columns "O:X".
To Select the last column with data in row x, use:
Cells(x, Cells(x, Columns.Count).End(xlToLeft).Column).Select
To Select the entire Range use:
Range(Cells(x, 3), Cells(x, Cells(x, Columns.Count).End(xlToLeft).Column)).Select
However, there is seldom a need to Select, if you "must" then it's better to first define a Range, like this:
Dim Rng As Range
Set Rng = Range(Cells(x, 3), Cells(x, Cells(x, Columns.Count).End(xlToLeft).Column))
And later on, if you need to Select it use:
Rng.Select

Use it like this:
Range(Cells(x,3), Cells(x, Range("C" & x).End(xlToRight).Column)).Select

Related

How to get VLOOKUP to select down to the lowest row in VBA?

Looking to automate the insertion of a VLOOKUP formula in a cell.
When recording the macro I instruct it to populate the columns below with the same formula. Works great, however, there is an issue when the table that the VLOOKUP searches through changes (more or less rows).
As it's recorded, the VLOOKUP drops down to the final row in the table (273). However, I want to set it up so that it will go down to the very last row. Meaning that I can run the script on tables of varying numbers of rows.
Selected columns will remain the same.
Range("AJ2").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-20], Previous!R2C2:R273C22,17,FALSE)"
try this:
With Worksheets("Previous")
Range("AJ2").FormulaR1C1 = _
"=VLOOKUP(RC[-20], Previous!R2C2:R" & .Cells(.Rows.Count, 2).End(xlUp).Row & "C22,17,FALSE)"
End With
where:
Range("AJ2")
will implicitly reference the ActiveSheet
.Cells(.Rows.Count, 2).End(xlUp).Row
will reference "Previous" worksheet, being inside a With Worksheets("Previous")- End With block
#nbayly said it, plenty of posts on this. Infact i have provided an answer to this before here:
How to Replace RC Formula Value with Variable
below is slightly modified for a dynamic range, which is what i believe you are looking for
For j = n To 10 Step -1
If Cells(j, 1).Value = "" Then
Cells(j, 1).Formula = "=VLookup(RC20,Previous!R2C2:R273C22,17,FALSE)"
End If
Next j
remember to define j as long and n=sheets("sheetname)".cells(rows.count,1).end(xlup).row
replace 10 in j = n to 10 with the starting row number

Return Column Header of Colored Cells

This process is being used for QC purposes. I have a spreadsheet that highlights certain cells that are wrong based off of their values and the validation rules we have in place. I was wonder if there was a way to return the column names of each cell that is colored into column A for each row? So for example if D2, F2, and G2 are wrong it would put all of those column headers in A2 to specify what exactly is wrong. I know it gets a bit more complicated trying to automate stuff with cell colors and I am not experienced in VBA which I'm assuming this will need. Is this possible to do, if so what would be the proper route to take? The data runs from column A to column BS, and the row numbers may differ, so if it could run up to row 1,000 that would be great. Attached is what the data looks like that I am working with.
The red means something is wrong in that row, and the orange cell is the color indicating that it is a wrong value
Yes, it is possible to do. Here is some snippets of code I pulled together to help get you started.
Lastrow = Cells(Rows.count, "A").End(xlUp).Row 'Get last row
With ActiveSheet
Lastcol = .Cells(1, .Columns.count).End(xlToLeft).Column 'Get last col
End With
For x = 1 To Lastcol 'Iterate Col
For i = 1 To Lastrow 'Iterate Row
'if red....
If Cells(i, x).Selection.Interior.Color = 255 then
'Move name to Cell A and append off of old name(s).
Cells(i, "A") = Cells(i, "A") & ", " & Cells(i, x)
End If
Next i 'next row
Next x 'next col

iteration of loop in formula vba

I'm trying to sum a variable range of data starting at row 3. sortedRow is the row # of the end of the data. lColumn is the last column used as a number.
I'm trying to sum the data in row 1, column H - lColumn.
I need to have the formula calculate the sum of column G, then iterating on referenced column by the current iteration (which will be columns h through x)
I've taken Scott Craner's advice and edited my code as
Dim lColumn As Long
lColumn = ActiveSheet.Cells(3, Columns.Count).End(xlToLeft).Column
sortedRow = Cells(Rows.Count, "D").End(xlUp).Row
Dim i As Integer 'iterated column sum cell
For i = 8 To lColumn
Cells(1, i).Value =Application.WorksheetFunction.SumIfs(Range(Cells(3,7),
Cells(sortedRow, 7)), Range(Cells(3, i), Cells(sortedRow, i)), 1)
Next i
The cells are not being updated with their values though.
It feels like I'm missing something really obvious with actually applying the number to the cell. I thought the above would do it.
added lColumn declaration because of issue with the formula being applied
added sortedRow declaration.
basically this. But with variable column lengths and number of columns.
It didn't matter for Column H that there was "#VALUE" in the volume column. So I assume it doesn't matter for the other columns.
Any help would be appreciated!
You have problems here.
("$G3:$G" & sortedRow, i & "3:" & i & sortedRow, 1)
("$G3:$G" & sortedRow & "," & i & "3:" & i & sortedRow, 1)
But you still have issues in there. If i=4 and sortedRow=12 let's say, this is what you would have.
(G3:G12,43:412, 1)
So you need to fix your Criteria_range1. I'm not clear from your question what you want the criteria to be.
Here is info on the arguments. https://msdn.microsoft.com/en-us/library/office/ff193011.aspx
The issue was resolved after fixing #VALUE cells in the sumifs columns I was trying to add. I made a conditional statement that set all errors to equal zero. This allowed the loop to function.

Excel VBA Match function not working

I'm using INDEX and MATCH functions to pull data which is concatenated string of G2 and H2 from column D (sorry I don't have enough points to attach pic). Column D has INDEX(column A and column B) and columns A and B have values till 12th row. MATCH is working fine giving me the position as 6 on the worksheet. But when I use this in VBA code as shown below,INDEX is working in the VBA code (can be seen through MsgBox) but MATCH function which would allot value to the variable 'check' isn't working. I have been breaking my head for really long. Need help from experts here. Somebody please tell me where am I going wrong?
Sub testindex()
Dim check As Long
Set sh = Sheets("Sheet1")
For j = 1 To 11
'Index value is correctly shown
MsgBox "Index Value=" & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 1) & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 2)
'Cells(7, 4)=ISA737775 same as G2&H2
MsgBox "Cells(7,4)=" & Cells(7, 4)
check = Application.WorksheetFunction.Match(Cells(7, 4), Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 1) & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 2), 0)
Next j
End Sub
Thanks
Match expects the second paramater to be in the form of a range. When you call match through VBA that range actually needs to be a range object, not just some string like "A1:A12" or whatever it is that your concatenated Index formulas output.
At any rate, you are iterating already, so why not just call those values directly instead of pulling their values through Index?
check = Application.WorksheetFunction.Match(Cells(7, 4), sh.Range("A" & 2 + j).value & sh.Range("B" & 2 + j), 0)
Which is writing the same exact thing but without having to use a taxing INDEX function in VBA to do it. Note that this still won't work because the second parameter of match is still just a string which is a concatenated value from Column A and Column B. You could convert to a range by sticking them in the range object with:
check = Application.WorksheetFunction.Match(Cells(7, 4), sh.Range(sh.Range("A" & 2 + j).value & sh.Range("B" & 2 + j)), 0)
I'm assuming that the values in A and B are actual cell names that when concatenated will make a range. Like when j=1 then the it would be like check=Match(Cells(7,4), sh.Range("G2:H50"), 0) or something...

Inside a loop, how to indicate "all rows" when taking the mean of multiple columns (Visual Basic)

I have a loop wherein I take the mean of several columns of numbers with the same number of rows each.
The point of the loop is to capture these means in a new vector.
So for each loop I need to indicate "all rows". In matlab this would be easy, just use ":" But I can't figure out what the analogy is in VB. Please help! Thanks.
(Please advise me as to what I put in the code below where I have ALLROWS).
My attempt so far:
For i = 1 To CA
mrCA11(i) = Application.WorksheetFunction.Average(revCA11(**ALLROWS**,i))
Next i
In matlab this would be:
For i = 1:CA
mrCA11(i) = mean(revCA11(:,i));
Next i
EDIT: I've also tried this trick to no avail:
For j = 1 To CA
For i = 1 To s11
temp11(i) = revCA11(i, j)
Next i
mrCA11(j) = Application.WorksheetFunction.Average(temp11)
Next j
I get the error message: "Unable to get the Average property of the Worksheet Function class"
As everybody (Tim and shahkalpesh at least) pointed out, we need to understand what is revCall or more specifically, we need to understand how you want to give them ALL ROWS in argument.
Finding the last row (or column or cell)
A common Excel issue is to find the last used row / column / cell.
This will give you the end of your vector.
Excel give you several methods to deal with this:
xlTypeLastCell
Last cell used in the entire sheet (regardless if it's used in column A or not)
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
End(xlUp)
Last cell used (including blanks in-between) in Column A is as simple as this:
lastRow = Range("A" & Rows.Count).End(xlUp).Row
End(xlToLeft)
Last cell used (including blanks in-between) in Row 1 is as simple as this:
lastRow = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Row
UsedRange
Last cell used in the WorkSheet (according to Excel interpretation):
Set rangeLastCell = ActiveSheet.UsedRange
Using an array as argument
The methods above told you how to find the last row (if this is what you need). You can then easily create your vector and use it in your procedure revCA11.
You can either give an array as argument as Tim pointed out in his answer with this kind of statement:
myArray = ActiveSheet.Range("A1", Cells(lastRow, lastColumn).Value
Or you can use the integer (or long) to build your vector inside your procedure as simple as declaring a range:
Range("A1:A" & lastRow)
You might clarify exactly how revCA11 is declared/created, but maybe something along these lines might work for you:
Sub Tester()
Dim arr, x
arr = ActiveSheet.Range("A1:D5").Value '2-D array
'average each column
Debug.Print "Columns:"
For x = 1 To UBound(arr, 2)
Debug.Print x, Application.Average(Application.Index(arr, 0, x))
Next x
'average each row
Debug.Print "Rows:"
For x = 1 To UBound(arr, 1)
Debug.Print x, Application.Average(Application.Index(arr, x, 0))
Next x
End Sub