Split a cell's formulaic elements into seperate cells - vba

So I have a cell with the formula =A+B, A and B are external values for which the external spreadsheet is no longer open. I was wondering if excel remembers the formula elements and if it was possible to get those element values into other cells. i.e.
Row Formula Value
1 =A+B 45
2 =ELEMENT(A1, 1) 10
3 =ELEMENT(A1, 2) 35
I can't imagine it being that simple though? I could seperate out the formula in vba using the + as a pivot, but this is not ideal as it would require the external spreadsheet to be reopened. If the external spreadsheet has to be reopened then I needn't bother trying to seperate the formula in the first place. I hope this makes sense and has an answer.

Your formula is already accessing those values in order to sum them in the open workbook. You do NOT need to re-open the workbook in order to evaluate the reference values, nor to parse the formula in the active workbook.
Assuming your formula references a closed workbook, with a simple sum function like:
='C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!$A$1 + ='C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!$B$1
You can parse the formula either in VBA or using string functions on the worksheet. As you note, for this example, parsing by the + operator will suffice. Since I think you understand how to do this, my example does not demonstrate how to parse the formula.
As long as you know or can obtain the references from the formula, you should be able to access those cells' values via formula, or programmatically in VBA using ExecuteExcel4Macro.
Sub GetValsFromClosedWorkbook()
Dim fileName As String
Dim filePath As String
Dim sheetName As String
Dim cellref As String
Dim myFormula As String
'This example might be one of the two arguments in your "A+B" formula:
' 'C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!A1
'## Assume you can properly parse the formula to arrive at these:
fileName = "test.xlsx"
filePath = "C:\Users\david_zemens\Desktop\"
sheetName = "Sheet1"
cellref = "A1"
'Concatenate in to R1C1 notation
myFormula = "='" & filePath & "[" & fileName & "]" & sheetName & "'!" & _
Range(cellref).Address(, , xlR1C1)
'## First, demonstrate that we can evaluate external references:
With Range("B1")
.Value = myFormula
MsgBox .Value
.Clear
End With
'## Evaluate the formula using ExecuteExcel4Macro:
MsgBox ExecuteExcel4Macro(Replace(myFormula, "=", vbNullString))
End Sub
Additional info
http://spreadsheetpage.com/index.php/tip/a_vba_function_to_get_a_value_from_a_closed_file/
Update
Based on OP's question of how this works (comments, below), I am not certain of how it works behind the scenes but here is my guess/explanation:
Firstly, keep in mind that a cell may have various properties like .Text, .Value, .Value2, .Formula etc. which in one way or another represent its contents.
The values aren't in the active file until the formula is evaluated, at which point Excel queries the external file and returns the current Value at that reference. Now the active file contains that Value as well as a Formula reference the external file.
As you continue working the active file preserves the Value and the reference, but may only update the value when prompted. For example, when you re-open the linked workbook, you will be prompted whether to "update external links".
if you say no, it will use the previously stored values (still preserves the Formula, it just doesn't evaluate it.
if you say yes, it will re-evaluate the formula (in case the value in the external file has changed) and return the new .Value
So, that's what I suspect is happening. If you're asking "How does Excel access the data inside an un-opened workbook" I don't really know how I just know that it does.

Related

Excel vba formula string: array formula - how to simulate Ctrl+Shift+Enter press

I have a worksheet with data and some columns which I fill with formulas via vba. The formula I struggle with is an array formula that looks like this:
Workbooks(job_file).Worksheets(1).Cells(h + b, 195).Formula = _
"{=IF(MAX(IF(B2:M2>$FY" & currentRow & ",$B$1:$M$1))=0,0," & _
"MAX(IF(sheet1!B2:M2>$FY" & currentRow & "," & _
"sheet1!$B$1:$M$1)))+1}"
It's supposed to be an array formula, so that's why I put {} there. However, when run it simply display the formula's text in a cell, without calculating it. I have to manually remove the brackets, and then press Ctrl+Shift+Enter myself.
Is there any way to avoid it? I have a great many rows and I can't ctrlshiftenter each.
I tried running it without brackets, it works, but gives a #VALUE! error, which can also be fixed by applying Ctrl+Shift+Enter.
To create an array formula with a simulated ctrl+shift+enter (aka CSE), use the Range.FormulaArray Property instead of the Range.Formula Property and let Excel add the 'curly braces'.
with Workbooks(job_file).Worksheets(1)
.Cells(h + b, 195).FormulaArray = _
"=IF(MAX(IF(B2:M2>$FY" & currentRow & ",$B$1:$M$1))=0,0," & _
"MAX(IF(sheet1!B2:M2>$FY" & currentRow & ", sheet1!$B$1:$M$1)))+1"
end with
I noticed in your formula that you use B2:M2 and sheet1!B2:M2. Shouldn't they both be sheet1!B2:M2?
There are some considerations.
Runtime Error: 1004 - Too long. There is a reduced character limit of 255 for FormulaArray but there are work-arounds.
Runtime Error: 1004 - Broken String. Remember that all quotes within a quoted string must be doubled up. This is easily one of the most common causes of errors when trying to write a formula into a cell through VBA. Hint: TEXT(,) can be used instead of "" so you don't have to type """" for a zero-length string.
FormulaArray accepts both xlR1C1 and xlA1 style formulas. If you can wrap your head around xlR1C1 style formula syntax, it is generally easier to construct a concatenated formula string in xlR1C1 since you can use digits to represent column numbers instead of trying to convert column ordinals to a column letter. However, do not try to mix-and-match xlA1 and xlR1C1 range references in the same formula; they must all be one style or the other.
If you are having trouble formulating a string that will be accepted as a formula, put a tick (e.g. ' ) in front of the first equals sign then run the code and return to the worksheet to see what was put in. Make modifications on the worksheet until you have a working formula then transfer those modifications to the VBA code.
As a note, it looks like this can be done without an array formula, like so:
Workbooks(job_file).Worksheets(1).Cells(h + b, 195).Formula = _
"=IF($FY" & currentRow & ">MAX(B2:M2),0," & _
"MAX(INDEX((B2:M2>$FY" & currentRow & ")*$B$1:$M$1,)))+1"

VBA Handeling of Excel Cell containing both Text and Formula-Value

I just started working with VBA for Excel and I ran into a problem I can't find the solution to. I want to make a macro that makes a copy of a sheet and renames the copy to what is specified in cell B8. Now, Cell B8 contains a string and a value (based on a formula) illustrated below.
Content of Cell B8
How do I get VBA to use the name (string and number) as the name of the new sheet?
Sub NewFunction()
Dim counter As Integer
Sheets(1).Copy After:=Sheets(1)
ActiveSheet.name = Sheets(1).Range("B8").CStr
End Sub
Thanks in advance!
For one, you can't use the "/" in the sheet name. It might error, but Excel will just ignore it.
Secondly, you are changing the name on the wrong sheet. You added a new sheet and then referred to the old sheet.
Thirdly, no need to use .CStr as the value of the cell is what you want, and since that is the default property, no need to use .Value either.
you were almost there
Sheets(1).Copy After:=Sheets(1)
ActiveSheet.name = Replace(Replace(Replace(Replace(Range("B8"), "\", "-"), "/", "-"), "?", "-"), "*", "-")
where
after Copy() method of Worksheet object, the new worksheet becomes the active one
the VBA Replace() method chain is to assure you're not using forbidden characters for your new worksheet name
there remains the issue of possible duplicate names, which can be handled via a specific Function you can find around here if you search for

Index Match 2 criteria in VBA

I have a macro I'm trying to create to map a bunch of old values to new values. At one point I need to do a match on 2 columns and get the value from a third column. In normal excel I would run the formula below, but as it is a Formula Array (have to CTRL+SHIFT+ENTER to run) I'm not quite sure how to get this to work in VBA
=INDEX($D:$D,MATCH(1,(E2=$A:$A)*(F2=$B:$B),0))
Any help appreciated
Have you tried?
Cell.FormulaArray()
It should work with normal notation, although it is intended for R1C1
There are essentially three ways to evaluate an array formula to a result within VBA.
The first is 'square bracket' evaluation. This processes a formula just as if it is on the worksheet.
Dim result As Variant
result = [INDEX('Sheet1'!D:D,MATCH(1,(E2='Sheet1'!A:A)*(F2='Sheet1'!B:B),0))]
Debug.Print result
Care must be given to explicitly show worksheet parentage. In the above, the full columns have been given a parent worksheet but the individual cells have not. The individual cells will default to the ActiveSheet property which may or may not even be in the same workbook. Define all cell references explicitly!
The second method is with Application.Evaluate method. This allows more freedom with the formulas using string construction.
Dim result As Variant, wsn As String
wsn = Worksheets("Sheet1").Name
result = Application.Evaluate("INDEX('" & wsn & "'!D:D, " & _
"MATCH(1, (E2='" & wsn & "'!A:A)*(F2='" & wsn & "'!B:B),0))")
Debug.Print result
Again, only the full column references have been given parent worksheet references. This should be fixed before run-time use. This method is better for array formulas because you can use string construction to cut the full column references down to the rows in the Worksheet.UsedRange property.
As mentioned, the third method involves writing the formula to a worksheet cell using the Range.FormulaArray property and retrieving the answer from the cell.

Excel use cell value as range in VBA

I have an excel file. There is a changable row quantity for column A for every time and that's why I need to make dynamic formula. For example;
I want to write "=LEN(B1)" formula on B1. And when make double click on right down corner of the cell, it's going to the end of until when column A values ends. That's why, before all this process, I wrote "=COUNT(A:A)" on cell C1.
In my VBA, I want to write;
Dim TEMP As String
TEMP = Range("C1").Value
Range("B1").Select
ActiveCell.FormulaR1C1="=+LEN(RC[-1])"
Selection.AutoFill Destination:=Range("B1:TEMP")
But there is something wrong in this process. As a result, I just want to use a cell value in my VBA as a range or string or number.
Thanks for your support.
Two notes:
It's best practice to always qualify your objects (workbooks, worksheets, ranges, etc.) beforehand
When you use R1C1 notation, you can just write the formula directly to the range (with no need for AutoFill or FillDown)
Try this:
Dim ws as Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1") 'edit for your sheet name
Dim lRow as Long
lRow = ws.Range("A" & ws.Rows.count).End(xlup).Row
ws.Range("B1:B" & lRow).FormulaR1C1 = "=Len(RC[-1])"
And just as a side note worth mentioning the way you wrote Range("B1:TEMP") is not proper syntax. Correct syntax would be Range("B1:B" & TEMP), which, of course, would only work if TEMP was indeed a numerical value :)

Writing formula into an Excel Range with Option Strict On

Is it possible to write formulas across a range in Excel from VB.Net? I'm using a String array to hold a list of formulas that I would like to apply to an Excel range, instead of looping through and writing them one at a time.
This line is what I am attempting to use to write to a range:
xlWorkSheet.Range("AF" & intCurrentRow.ToString & ":AG" & intCurrentRow.ToString).Formula = formulas
The formula is being written to Excel, but Excel is actually displaying the formula, instead of the calculated value. If I write each formula to each cell like this:
xlWorkSheet.Range("AF" & intCurrentRow.ToString).Formula = formulas(0)
xlWorkSheet.Range("AG" & intCurrentRow.ToString).Formula = formulas(1)
It works perfectly fine and Excel displays the calculated values as it should. Almost seems like I'm missing a step but I haven't been able to find anything in my research.
As soon as I hit post I figured out the problem. Instead of using the .Formula property of an Excel.Range, you have to use the .FormulaArray property instead.
xlWorkSheet.Range("AF" & intCurrentRow.ToString & ":AG" & intCurrentRow.ToString).FormulaArray = formulas