Variable Range Used for a Formula - vba

I recorded the below code for use in my macro, but it would only be useful if that range never changes.
Because the range does change each time I run it, how can I change "A1:E2" into variables to account for a changing range?
I don't think xlLastCell would be a correct usage in this case.
I know how to get the column number and row number of the ending cell, but I couldn't figure out how to incorporate that into my code.
ActiveCell.Offset(2, 0).Range("A1:E2").Select
Selection.FormulaR1C1 = "0"

I know how to get the column number and row number of the ending cell, but I couldn't figure out how to incorporate that into my code.
Like this:
Dim myRange as Range
Set myRange = Range(Cells(1,1), Cells(lastRow, lastColumn))
myRange.FormulaR1C1 = "0"
In the above code, myRange is defined by two cells, one at (1,1) (row 1, column 1) and another at (lastRow, lastColumn) which would be the vairables you identifed as the ending row/column.

Related

Excel VBA: How do I assign a range to a variable?

The current code is as follows:
With Sheets(sheetChk)
a = .Range(chkCell, .Range(Left(chkCell, 1) & Rows.Count).End(xlUp)).Value
End With
sheetChk is defined as the desired sheet index.
chkCell is defined as the desired "first cell" in the range.
I am attempting to assign a range to a. The problem is that the above code grabs the last cell in the column, entirely. Rather, I want to end at a specific row as I have other data in the same column after the desired range that needs to be ignored. How can I accomplish this?
First to assign a range, you need to have a Set first.
Example: Set a = Range("A1")
Another problem I see is that you're putting a .value at the end. That doesn't make sense for a range.
If you want to specify a specific row, then you need to include that in the code instead of using end(xlUp).
Example if it's row 50:
With Sheets(sheetChk)
Set a = .Range(chkCell, .Range(Left(chkCell, 1) & 50).End(xlUp))
End With
What you're currently using is finding the bottom row being used, which doesn't sound like you want. If you want to go the other direction (i.e. from the starting cell down until there's an empty cell), you can use this code:
With Sheets(sheetChk)
Set a = .Range(chkCell, .Range(Left(chkCell, 1) & chkCell.Row).End(xlDown))
End With
Based on your code, it looks like you might be putting an address in whatever cell chkCell is. If you have the row in that cell, and assuming you never exceed column z, then you could use this code to find the row:
With Sheets(sheetChk)
Set a = .Range(chkCell, .Range(Left(chkCell, 1) & Right(chkCell,Len(chkCell)-1))
End With
If that doesn't work, you need to figure out some method determine what row to use. Hope that helps.
dim rng as range
set rng = thisworkbook.sheets("sheet1").range("a1:a666")

IF() Multiple Cells are equal then "TRUE" with only taking number values in a range

I am trying to write a formula to take only number formats from a row to in order to use an IF formula that illicit the value of "No" if all cells are equal to each other.
See a snippet of my file here:
The problem I am having is that the formula is taking the blank cells (no formats) and counting them in the equation still, so all of my values are "Yes". How do I let my formula only calculate from cells that have numbers in them for each row? I have tried the IFNUMBER(), IFEMPTY() etc... but I am not sure I am employing these correctly e.g. nesting into my formula. I need to ignore the blanks in each row.
Note: I need to only take the cells with number values. I have cleared the contents of values of the rows that do not have number values.
Here is the equation that I currently have:
=IFERROR(IF(AND(ROUND($E2,3)=ROUND($F2,3),ROUND($F2,3)=ROUND($G2,3),ROUND($G2,3)=ROUND($H2,3),ROUND($H2,3)=ROUND($I2,3),ROUND($I2,3)=ROUND($J2,3),ROUND($J2,3)=ROUND($K2,3),ROUND($K2,3)=ROUND($L2,3),ROUND($L2,3)=ROUND($M2,3),ROUND($M2,3)=ROUND($N2,3)),"No","Yes"),"")
Note: this is taking blanks and counting them (as stated from above). It should produce a "Yes" if there are numbers different in the column and a "No" if there are no numbers differences. Currently, it is always producing a "Yes" because it is counting the blanks in the columns.
I am open to a vba solution as well, I have the following from code, but I do not know how to set the range for each row to only look for number formats:
Here is my vba code:
Dim arng As Range
Dim aworkrng As Range
Dim brng As Range
Dim bworkrng As Range
On Error Resume Next
Set aworkrng = Range("O2:O1550")
Set bworkrng = Range("E2:N1550")
Set brng = Range("E2:N2")
On Error Resume Next
For Each arng In aworkrng
If Not IsEmpty(brng.Value) Then
arng.Formula = _
"=IFERROR(IF(AND(ROUND(RC5,3)=ROUND(RC6,3),ROUND(RC6,3)=ROUND(RC7,3),ROUND(RC7,3)=ROUND(RC8,3),ROUND(RC8,3)=ROUND(RC9,3),ROUND(RC9,3)=ROUND(RC10,3),ROUND(RC10,3)=ROUND(RC11,3),ROUND(RC11,3)=ROUND(RC12,3),ROUND(RC12,3)=ROUND(RC13,3),ROUND(RC13,3)=ROUND(RC14,3)),""No"",""Yes""),"""")"
Range("O3").Select
End If
Next
If anyone can help me on this, I would great appreciate it!
Try:
=IF(MIN(E2:N2)=MAX(E2:N2),"No","Yes")

Creating a dynamic range between two named cells with set number of columns

I need to create a dynamic range between two named cells (the cells and corresponding rows shouldn't be included in the selection). The number of columns is always the same (4), only the number of rows is changing. That's the first step.
Second one is putting several these ranges into a numbered list in another excel list, but that is something I can hopefully figure out myself. Thank you very much.
I might try something like this:
Sub RangeBetween()
Dim rng1 As Range, rng2 As Range
Dim betRange As Range
Set rng1 = Range("A1") 'sample data
Set rng2 = Range("A20")
Set betRange = Range(rng1.Offset(1, 0).Address & ":" & rng2.Offset(-1, 3).Address)
End Sub
This is of course assuming that your named cells are along the same column. If your named cells always spread 4 columns by default, replace the Offset(-1, 3) with Offset(-1, 0).
This code defines a named range with the name "NewNamedRange". The code assumes (and requires) that your bracketing cells are already named ranges, with the names "UpperLeft" and "LowerRight". The offset formulas exclude the bracketing cells from the named range. So if "UpperLeft" is cell D2, and "LowerRight" is cell G22, "NewNamedRange" will be the range "D3:G21". Because the named range definition is a formula, NewNamedRange will change dynamically as the bracketing cell definitions change. Hope this helps.
Sub NamedRange()
ActiveWorkbook.Names.Add _
Name:="NewNamedRange", _
RefersTo:="=OFFSET(UpperLeft,1,0):OFFSET(LowerRight,-1,0)"
End Sub

Finding average of selection and then assigning it to a cell

I am attempting to create some dynamic code that, at this point, will select a bunch of cells, move the selection over two columns, then find the average of that selection and send that value to a cell. This is what I have so far, I am getting stuck at averaging the selection I've made:
Sub StatMakersub(Rng1 As Range)
Dim MyRange As Range
Dim Cell As Object
Dim InQuestion As Range
Dim SelAvg As Object
'Check every cell in the range for matching criteria.
For Each Cell In Rng1
If Cell.Value = 2000 Then
If MyRange Is Nothing Then
Set MyRange = Range(Cell.Address)
Else
Set MyRange = Union(MyRange, Range(Cell.Address))
End If
End If
Next
'Select the new range of only matching criteria
MyRange.Select
Selection.Offset(0, 2).Select
Set InQuestion = Selection
Range("P2").Formula = "=Average(Selection)"
Range("Q2").Formula = "=STDDEVA(Selection)"
End Sub
I can't find much on the web about how to average range variables.
You can calculate the average of a selection in this way:
Application.WorksheetFunction.Average("Here you put your range")
The result is a value and not an object, so you should use a variable. Taking names from your case you should use it like this:
SelAvgResult = Application.WorksheetFunction.Average(InQuestion)
I put another name for the variable, but you may still use SelAvg if you like. Just remind to define it as a variable (you may choose your desired format depending on the data size) instead of object if you do not need it anymore.
You may use then this variable for setting the value of your desired cell.
I have a last note: your code seems to replicate the already existing formula AVERAGEIF. If your criteria column is for instance column A and value you should use for calculating the average are in column C, You could directly set the value of the cell where you want the average like this:
=AVERAGEIF(A:A, "2000", C:C)
In this case you would avoid VBA.
Have you tried using the Sum worksheet function for calculating the sum of the range?
Xsum = WorksheetFunction.Sum(arrayX)
and dividing the Xsum value with the length of the array?
One thing I should metion is that you do not need to select the range to work with it. You can use it directly and doing so will also improve how fast your code runs.
To insert your worksheet functions, use the Range.Address function to generate a cell reference to put into the formulas.
https://msdn.microsoft.com/en-us/library/office/ff837625.aspx

Range address, where do I find the sheet?

I work on a UDF and the user inputs a range, say "sheet1!A1:C8".
In the VBA I write the following:
Function RelativeSearch(Search, rng As Range, Row, Column)
MsgBox rng.Address
Here the msgbox only gives me A1:C8. How can I get the "Sheet1"?
I have tried to make rng as string but that does not work as I have to use rng.find later in the code.
Anyone know of a way to get the sheet from the range?
The Range object has a Worksheet property, so:
rng.Worksheet.Name will do what you want.
In addition the Address property has an External argument, so:
rng.Address(External:=True) yields the entire range address, e.g., [Book1]Sheet1!$D$28.
To get a reference to the Sheet, use rng.Parent.
In your specific case, you are looking for rng.Parent.Name.
So you could do
MsgBox rng.Parent.Name & "!" & rng.Address
This is not an answer to the question you asked, but I suspect it might help you avoid having to ask the question.
If you are trying to find, within rng, the value passed as Search, and then return a value derived by some offset by Row and Column, there is no need to know what worksheet rng is on:
Excel formula (perhaps in cell Sheet4!D6):
=RelativeSearch("b",Sheet1!A1:A6,3,2)
Code which will search the range A1:A6 in Sheet1 for the value "b" and then return the value from the cell that is 3 rows below and 2 columns to the right:
Function RelativeSearch(Search, rng As Range, Row, Column)
Dim r As Range
Set r = rng.Find(What:=Search, LookIn:=xlValues, LookAt:=xlWhole)
If r Is Nothing Then
RelativeSearch = CVErr(xlErrNA)
Else
RelativeSearch = r.Offset(Row, Column).Value
End If
End Function
(If you want it to be consistent with VLOOKUP's syntax, you will need to use r.Offset(Row - 1, Column - 1) rather than r.Offset(Row, Column).)