VBA use variable value as cell reference in formula - excel

I am trying to enter a "=$M15-$N15" formula to cell A15. However, need to use variable (r) instead of 15 as I don't know that value until later in the code. Trying the below but it is not working. What am I doing wrong?
Range("A" & r).formula = "="$M" & r - "$N" & r"
after the code is run, I need to have a formula ($M15-$N15) in Cell A 15.

I suspect you're looking for the INDIRECT function. An example of this, based on your explanation, would look like:
=INDIRECT("M"&A1)-INDIRECT("N"&A1)
If you're actually looking for VBA, you could use the following:
Range("A" & r).formula = "=$M" & r & "-$N" & r
However, this makes me suspect this is part of some over-arching routine, and, without knowing more, I can only speculate there might be a better or more efficient method(s) for going about it.

Related

Excel VBA conditional formatting based on another column and cell value [duplicate]

I've got an Excel spreadsheet, with a Macro, that inserts a conditional formatting, like this:
Selection.FormatConditions.Add Type:=xlExpression, Formula1:="=UND($A3=""" & lastName & """; $B3=""" & firstName & """)"
As you can see, I've used the German formula for "AND" (i.e. "UND"), and obviously, this code doesn't work as soon as I use it on a French or English version of Excel.
Usually formulas are localized automatically, but how can I insert a formula during run-time that will work on ALL versions?
Ok, thanks for helping me with this, you've helped me crack this one.
It is indeed not possible to just use English. One can use English when operating on a formula, eg. by setting coding Range("A1").formula="AND(TRUE)", but this does not work with FormatConditions.
My solution is a function that writes a formula temporarily to a cell, reads it through the FormulaLocal property, and returns the localized formula, like so:
Function GetLocalizedFormula(formula As String)
' returns the English formula from the parameter in the local format
Dim temporary As String
temporary = Range("A1").formula
Range("A1").formula = formula
Dim result As String
result = Range("A1").FormulaLocal
Range("A1").formula = temporary
GetLocalizedFormula = result
End Function
The returned formula can be used on FormatConditions, which will be re-localized or un-localized when the document is later opened on a different-language version of Excel.
I just found a very elegant solution to the problem in a German Excel forum. This doesn't write to a dummy cell but rather uses a temporary named range. I used the original idea (credit to bst) to write a translating function for both directions.
Convert localized formula to English formula:
Public Function TranslateFormula_LocalToGeneric(ByVal iFormula As String) As String
Names.Add "temporaryFormula", RefersToLocal:=iFormula
TranslateFormula_LocalToGeneric = Names("temporaryFormula").RefersTo
Names("temporaryFormula").Delete
End Function
Convert English formula to localized formula:
Public Function TranslateFormula_GenericToLocal(ByVal iFormula As String) As String
Names.Add "temporaryFormula", RefersTo:=iFormula
TranslateFormula_GenericToLocal = Names("temporaryFormula").RefersToLocal
Names("temporaryFormula").Delete
End Function
This is very handy if you need to deal with formulas in conditional formatting, since these formulas are always stored as localized formulas (but you could need their generic version, e.g. to use Application.Evaluate(genericFormula)).
Store (a trivial version of) the formula in a (hidden) cell in your workbook.
Then when you open the workbook that formula will be translated automatically by excel for the user.
Now you just have to dissect this formula in your script (find the opening bracket "(" and take the past left of that:
Use something like:
strLocalizedFormula = Mid(strYourFormula, 2, InStr(1, strYourFormula, "(") - 2)
where strYourFormula will be a copy from the formula from your worksheet.
I hope this works as I only use an English environment.
Also from reading this:
http://vantedbits.blogspot.nl/2010/10/excel-vba-tip-translate-formulas.html
I am thinking you should (only) be able to use the english version of a cell formula from VBA.
Maybe try this (untested as I only have English version insatlled)
Write your international version of the formula to an out of the way cell using Range.Formula . Then read it back from Range.FormulaLocal, and write that string to the FormatConditions
I know this thread is ages old, and someone may have found an elegant solution, but I just had the same problem where I needed to apply conditional formatting without modifying the sheet, creating temporary cell contents or named ranges. All users use English language versions of Excel, so the functions used in the formulas are the same, but the regional settings vary by location, and therefore also the parameter separater; In Norwegian, it's ";" instead of ",", much like the rest of Europe, I guess.
For example, I needed to automatically create conditional formatting, using Excel formula for the following criterion:
.FormatConditions.Add xlExpression, Formula1:="=AND(ISNUMBER(B" & I & "),B" & I & ">=" & Ul1 & ")"
Where "Ul1" is a value defined in a previous step, and it's not important for the solution.
However, I needed to be able to run this on computers with both Norwegian and English settings
I and found a very short and simple solution from Andrew Pulsom here: https://www.mrexcel.com/board/threads/french-vba-vs-english-vba.729570/. He just made the parameter separator into a variable:
If Application.International(xlDecimalSeparator) = "," Then
Sep = ";"
Else
Sep = ","
End If
Cl1 = "=AND(ISNUMBER(B" & I & ")" & Sep & "B" & I & "<" & Ul1 & ")"
Worked like a charm for me :)
I know that this only solves part of the problem, but I assume that this could apply to many international companies which use English Office installations with local regional settings.
Thanks everyone! I found the post very useful.
My solution is a combination of others, I add it in case somebody finds it useful.
Dim tempform As String
Dim strlocalform1 As String
Dim strlocalform2 As String
' Get formula stored in WorksheetA Cell O1 =IFERROR(a,b)
tempform = Worksheets("Sheet").Range("O1").Formula
' Extract from the formula IFERROR statement in local language.
strlocalform1 = Mid(tempform, 2, InStr(1, tempform, "(") - 1)
' Extract from the formula separator , (comma) in local settings.
strlocalform2 = Mid(tempform, InStr(1, tempform, "a") + 1, 1)
' Add formula in local language to desired field.
pvt.CalculatedFields.Add Name:="NewField", Formula:="=" & strlocalform1 & "FORMULA" & strlocalform2 & ")"
Hope this helps!
Please refer to the link for more explanation: https://bettersolutions.com/csharp/excel-interop/locale-culture.htm
CultureInfo baseCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo(xlapp.LanguageSettings.LanguageID(Office.MsoAppLanguageID.msoLanguageIDUI));
// do something
System.Threading.Thread.CurrentThread.CurrentCulture = baseCulture;

Using the cells function inside a formula

Let's say we have this piece of code as an example
Worksheets"Sheets1".Cells(1,4).Formula= "=SUM(Cells(x1,y1):Cells(x2:y2))"
Is there anyway to make this work ?
The idea is that if I were to put this piece of code in a sub-routine, I could make the range of the sum dependent on the results of the subroutine.
Example, If I were to write a subroutine that counts how many cells have numbers on them (for example 20), I could then use that as range.
So something like this
count = 20
Worksheets"Sheets1".Cells(1,4).Formula= "=SUM(Cells(1,1):Cells(count:1)"
I would want this to be equivalent to writing =SUM(A1:A20)
Is it possible ?
Like this?
Worksheets("Sheets1").Cells(1,4).Formula= _
"=SUM(" & Cells(1, 1).Resize(count, 1).address & ")"

Dynamic file names with Excel INDEX() function

I'm doing some data crunching work in Excel. What I need to do is to fetch values from a Cell (Say D3) from sequentially numbered workbooks like 1.xlsx, 2.xlsx, 3.xlsx...so on.
I can't use INDIRECT() function as it would require all the target files to be opened (which is not possible in my case). So, I'm using the INDEX() function with the following values:
INDEX( [1.xlsx]Sheet1!D:D, 1,1 )
Now, I want the bold part of the formula to be dyamic based on the number on left column as shown in the image below:
Somebody please suggest solution to the problem at hand as I'm tired on googling :)
Thanks in advance.
Perhaps someone will prove me wrong, but I don't believe it is possible to generate such dynamic referencing without resource to INDIRECT, unless you are happy with a longhand (and static) method such as:
=INDEX(CHOOSE(ROWS($1:1),[1.xlsx]Sheet1!D:D,[2.xlsx]Sheet1!D:D,[3.xlsx]Sheet1!D:D),1,1)
though this requires that each workbook reference be entered explicitly within the formula. As such, this also means that these cannot be created via reference to any cells within the worksheet, as you might have hoped.
Or, if VBA is an option:
Sub Indexing()
Dim i As Long
For i = 2 To Cells(Rows.Count, 1).End(xlUp).Row
Range("B" & i).Formula = "=INDEX([" & Range("A" & i).Value & ".xlsx]Sheet1!D:D,1,1)"
Next i
End Sub
Regards

Dynamic Vlookup with usage of indirect

I'm having trouble with the usage of Indirect function.
Here's what i'm looking for, I'm trying to create a dynamic vlookup based on the current tab.
=VLOOKUP(B3;'NH BBC'!$E$1:$Z$188;MATCH("Share Outstanding";'NH BBC'!$E$1:$Z$1;0);0)
My plan is to modify the 'NH BBC' by 'NH ' & RIGHT(CELL("filename");3) Supposing that the name of my tab is XXX_BBC.
I've tried to use indirect function but I'm not sure I'm on the good way.
Here's what I've tried:
=VLOOKUP(B3;INDIRECT("'" "NH " & "RIGHT(CELL("'" & "filename" & "'" & ");3)" & "!" & "E1:Z188");MATCH("Share Outstanding";'NH BBC'!$E$1:$Z$1;0);0)
Hope I've been clear.
Thanks in advance !
You are trying to concatenate some text with the results returned from a formula, but you are sticking the formulas in quotes, turning them into text. Furthermore, you are not keeping very good track of your text. There are quotes all over the place. Take this bit by bit in a seperate cell if need, slowly growing your formula from the inside out so you can insure everything is as expected. Right now it's a mess.
INDIRECT("'" "NH " & "RIGHT(CELL("'" & "filename" & "'" & ");3)" & "!" & "E1:Z188")
Should be:
INDIRECT("'NH " & RIGHT(CELL("filename");3) & "'!E1:Z188")
No need for all the complication.
I've finally found and this formula is working perfectly.
VLOOKUP($B3;INDIRECT("'NH "&RIGHT(CELL("filename");3)&"'!$G$1:$ZZ$9999");MATCH("SHARE_OUTSTANDING";INDIRECT("'NH "&RIGHT(CELL("filename");3)&"'!$G$1:$ZZ$1");0))
By the way the issue i've got is that the cell are changing when i'm using the formula in another tab. Is this possible to look the value i've obtained ?
Something like a F9 ?

Indirect Average of unspecified length array of differences

I have the following indirect reference:
=AVERAGE(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3))
On 'Pages'!D3 I have another page '1D_3' and on 'Pages'!J3 I have 2:2.
I need to alter the above code to instead find the average of the differences between each successive value. I can only change the value in 'Pages'!J3 (2:2) and I can change the equation above.
From this reference http://www.excelforum.com/excel-general/742194-difference-between-consecutive-number.html I have come up with how I can do the difference between each successive, but only if I have a known range. Ex. For elements A1:G1,
=SUM(A1:F1-B1:G1)
I could then do the following for the average:
=SUM(A1:F1-B1:G1)/(COUNT(1:1)-1)
But I do not know how to do the SUM part if I have an unspecified range. I also am unsure of how to implement this in the INDIRECT function.
Just some additional background info that may clarify this, The values in the array are times from a stopwatch. It was assumed that each value would be a time difference, but instead it is just the time on the stopwatch (Ex. 0.0015, 1.0034, 2.356, etc.). I want to find the average time duration between each value.
Any help would be greatly appreciated.
Before solving the formula you seek, let me just point out that all you need is the (EndValue-StartValue)/NumberOfEntries - no need to calculated the difference of each timing point first, as this will cancel itself out in the final calculation anyway.
Now assuming that Pages!J3 still only contains the row number, i.e. the formula =INDIRECT("'" & Pages!D5 & "'!" & Pages!J3) will return you a reference to this row. In the following formula, I use X as an replacement for the INDIRECT formula, to make it more readable:
=(OFFSET(X,0,0,1,1)-OFFSET(X,0,COUNT(X),1,1))/COUNT(X)
Now you only need to replace X with the above formula - or simply add a named range with the formula. If you combine it, you'll end up with this formula:
=(OFFSET(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3),0,0,1,1)-OFFSET(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3),0,COUNT(X),1,1))/COUNT(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3))
I tried what the other poster suggested and it did not work, even when replacing the remaining 'X'. I worked through a few other examples in Excel to finally come to the following conclusion. To not let this be lost to the sands of the internet, I decided to post my own solution. So I wanted an average of the differences between time values. Essentially, I wanted a sum over the total number of times (mean). The difficulty was in the indirect referencing and INDIRECT referencing within an INDIRECT reference.
So what I had was data on multiple worksheets, pages (Pages on B through E columns) and ranges (Pages on J column) on another worksheet, and the resulting operations on another sheet.
=SUM(INDIRECT("'"&Pages!D5&"'!C2"):INDIRECT("'"&Pages!D5&"'!"&SUBSTITUTE(ADDRESS(2,COUNTA(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3)),4),"1",""))-INDIRECT("'"&Pages!D5&"'!B2"):INDIRECT("'"&Pages!D5&"'!"&SUBSTITUTE(ADDRESS(2,COUNTA(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3))-1,4),"1","")))/(COUNT(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3))-1)
To break this into parts, we have:
=SUM(junk)/COUNT(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3))-1
And the 'junk' part is as follows. Ultimately, it was in the form:
=SUM(A1:F1-B1:G1)
Without INDIRECTs, if we had a page of data named '8D_2FU':
=SUM('8D_2FU'!C2:AW2-'8D_2FU'!B2:AV2)/(COUNT('8D_2FU'!2:2)-1)
Note that for this implementation we pick a maximum column on AW which was fine for all possible datasets.
There is also one more part of interest in the 'junk'. You cannot make an INDIRECT reference within an INDIRECT reference, so to fool Excel, we can use the SUBSTITUTE command and get the same result by converting the address contained in the INDIRECT reference.
SUBSTITUTE(ADDRESS(2,COUNTA(INDIRECT("'" & Pages!D5 & "'!" & Pages!J3)),4),"1",""))
Finally, to use this, you must make this an array operation by instead of typing 'Enter' you must type, CTRL+SHIFT+Enter. The result was also confirmed using a brute force test case.

Resources