How do I update formula range in a macro? - excel

I have a formula in A1 that is fed with data from a different workbook. It's only a reference to this other workbook, there aren't any calculations.
This second workbook is updated on a monthly basis so the cell I'm interested in referring to is offset one cell to the right each month.
How can I write a macro that tells my current formula in A1 to use the same formula but moving it one place to the right? It'd be something like: [Book1]Sheet1!C15 to [Book1]Sheet1!D15. Thanks!

Use Range.Precedents to get the cells a particular Range depends on.
'get the cell:
Dim theCell As Range
Set theCell = ActiveSheet.Range("A1")
'get its first "precedent" Range:
Dim precedent As Range
Set precedent = theCell.Precedents(1)
'rewrite the formula, offsetting the precedent by 1 column:
theCell.Formula = "=" & precedent.Offset(ColumnOffset:=1).Address(External:=True)
Obviously this makes a lot of assumptions and will need to be adjusted to your specific needs, but you don't need to parse any formulas to offset its precedent cells when you're looking at a formula that's simply =SomeCellAddress.

First put this small UDF in a standard module:
Public Function NextCellOver(s As String) As String
arr = Split(s, "!")
addy = Range(arr(1)).Offset(0, 1).Address
NextCellOver = arr(0) & "!" & addy
End Function
It will accept a string that ends with something like !Z99 and return a string ending with !AA99. (Basically one column to the right.)
Then enter:
Sub marine()
With Range("A1")
.Formula = NextCellOver(.Formula)
End With
Application.CalculateFullRebuild
End Sub
To apply this to the cell in question.

Related

Switch Worksheet Names without Updating References to those Sheets

My file has two identical Worksheets for users to input two different sets of assumption variables, called "InputA" and "InputB". I want to quickly switch which Input sheet is feeding into the other sheets of the model.
Using Find and Replace took over 5 minutes, and there were over 350,000 references to "InputA".
I tried the following macro, which takes an instant to run, but unfortunately also changes all references in the workbook, effectively keeping everything referenced to the original input sheet.
Sheets("InputA").Name = "temp"
Sheets("InputB").Name = "InputA"
Sheets("temp").Name = "InputB"
Is there a way to execute the macro but prevent any references to worksheets from changing to the new sheet name, basically freezing everything except the sheet name change? Or perhaps any other solution that will work quickly? I don't want to go through 350,000 instances and rewrite using INDIRECT(), as that is the only other solution I've seen, because my references are complex and nested and that will take an age.
Thanks.
Assuming that your 2 Input-Sheets have the same structure, I would suggest the following:
Create a named range on Workbook-level, name it for example InputData. This range should contain all data from InputA.
Create a helper-sheet and name it Input - you can later set it to hidden.
Mark the range in the new sheet that is exactly the size of the Input-Data-Range and enter the formula =InputData as Array-formula. You can do so by entering Ctrl+Shift+Enter. The formula should have curly brackets and the sheet should now display the data of InputA.
Change all you formulas to refer to the helper Sheet Input instead of InputA.
Create a macro:
Sub switchInput()
Const sheetAName = "InputA"
Const sheetBName = "InputB"
With ThisWorkbook.Names("inputData")
If InStr(.RefersTo, sheetAName) > 0 Then
.RefersTo = Replace(.RefersTo, sheetAName, sheetBName)
Else
.RefersTo = Replace(.RefersTo, sheetBName, sheetAName)
End If
End With
End Sub
This routine will just change the definition of the named range to point either to the first or second input sheet. As a consequence, the helper sheet will show the data of the selected Input-Sheet. All your formulas itself stays unchanged.
As stated in the comments, you could take the approach recommended by Damian and use a conditional in all relevant cells. The generic conditional would be
=IF(A1="InputA",FORMULA INPUTA,FORMULA INPUTB)
This formula makes A1 the cell that decides which input to pull. This will make changing the around 350.000 output formulas in your workbook the bottleneck, the following macro takes care of changing all the formulas to conatin the conditional:
Sub changeFormulas()
Dim rng As Range, cll As Range
Set rng = shOutput.Range("A2:C10") 'Your relevant worksheet and range here
Dim aStr As String, bStr As String, formulaStr As String
aStr = "InputA"
bStr = "InputB"
For Each cll In rng
If cll.HasFormula And InStr(1, cll.Formula, aStr, 1) Then
formulaStr = Right(cll.Formula, Len(cll.Formula) - 1)
cll.Formula = "=IF(A1=" & Chr(34) & aStr & Chr(34) & "," & formulaStr & "," & Replace(formulaStr, aStr, bStr) & ")" 'Change A1 to the reference most suited for your case
End If
Next cll
End Sub
This might take a bit of time, since it has to access all the relevant cells one by one, but it will only have to run once.
To explain: This macro will go through all the cells in your range rng specified at the top. If a cell has a formula in it and the formula contains "InputA" it will change that formula to fit the generic conditional (with the cells own formula of course). Chr(34) is the quotation mark ", I find using Chr(34) more readable than multiple quotation marks """, but that is just preference.

Is there a way to use the sheet name from a certain cell (which has been populated using that sheet) to populate another cell?

Let me try to be more clear:
Here's an image that illustrates what I'm trying to do.
Essentially, my goal would be to have a formula that I could put into cell A2 (or a macro, if necessary) that would insert the name of the sheet that cell B2 comes from. In this case, that would be Sheet2. I've tried a bit through the macro recorder, but I haven't been able to get anything to work the way I want it to.
Ideally, I'd be able to select a cell (in this case, cell A2) and activate a macro or put in a formula that would populate that cell (A2) with the Sheet that the cell to the right of it (B2) comes from.
Thanks a ton for your help, any guidance as to what I should use for this or how I could do this would be hugely appreciated.
Here's a UDF that will pull the sheet name for a simple =SheetX!RANGE formula. It will also alert if there are multiple sheet references or none at all.
Place this in a standard module and in a cell type =ReturnSheet(B2)
Function ReturnSheet(rng As Range) As String
Dim sFormula As String
sFormula = rng.Formula
If InStr(1, sFormula, "!") = 0 Then
Dim sSheet As String
sSheet = "No sheet precedents found!"
Else
If UBound(Split(sFormula, "!")) = 1 Then
sSheet = Mid(sFormula, 2, InStr(1, sFormula, "!") - 2)
Else
sSheet = "Multiple Sheet precendents!"
End If
End If
ReturnSheet = Replace(sSheet,"'","") 'replace single quote in sheet names that has spaces
End Function

Use CELL on an array to return string made of types of the cells

Lets say we have 5000 rows with random values (blanks, numbers, characters). I need to show type of all the cells in these 5000 rows in a single cell using a formula. Is it actually possible? I've tried to CONCATENATE(CELL("type";array)) and ctrl+shift+enter but it didn't work (it returns the type of the first cell in the array).
If you want to know, this is for finding a cell with text rather than values or blanks in a very big file. Maybe you have a better solution.
Thanks in advance.
UPD: thanks for macros but I can't use them in this workbook, I need a formula-solution.
UPD: I've got how to do it with conditional formatting => new rule => use a formula to determine... => use ISTEXT('first cell of the range') formula
But still, is it possible to create the formula?
The best way to go about this is to use MACROs
Here is my sample code:
Sub Button2_Click()
numRows = 10 ' Number fo rows to loop through, in your case 5000
'loop through each cell located in column 1
'Check its type
'Concatenate each one in 1 cell on the 8th column
For i = 1 To numRows
Sheet1.Cells(1, 8).Value = Sheet1.Cells(1, 8).Value & TypeName(Sheet1.Cells(i, 1).Value) & ","
Next i
End Sub
You can adapt this small user defined function to your needs.
Say we are looking at cells in the first row, from A1 through D1 and we want to concatenate their types into a single cell. Enter the following UDF() in a standard module:
Public Function KonKaType(rIN As Range) As String
Dim r As Range
For Each r In rIN
s = "cell(""type""," & r.Address(0, 0) & ")"
KonKaType = KonKaType & Evaluate(s)
Next r
End Function
and then in the worksheet cell E1 enter:
=KonKaType(A1:D1)

how to specify a range in vba using a cell value in excel

I am very new to vba and basically only use it when amending a range value (having previously recorded the script using a macro in excel). Since I add/delete rows in excel I have to go to the vba script and manually update the range part. So if my range on the excel sheet has expanded from A2:R83 to A2.R84 heres one of the parts I update from:
Range("A2:R83").Select
To:
Range("A2:R84").Select
Is there a way I can specify a cell that vba can take the range values from? eg can I, on the excel sheet cell X1 input A2 and in cell Y2 input R84 and have the vba script reference these cells to determine the current range?
Appreciate any help!
I believe this will do what you want, :
Sub test()
Dim s1 As String, s2 As String
s1 = Sheet1.Range("A1"): s2 = Sheet1.Range("B1")
Range(s1 & ":" & s2).Select
End Sub
You will, however, run into trouble if the values in A1 and B1 are not valid cell-names, so some input validation may be a good idea.
I found that it is possible to make the validation range dinamic using INDIRECT.
1.- In location that you choose (in the example I use X1 in sheet1) put
="'Sheet1'!"&"A2:"&"R"&COUNTA(R1:R2000)
I put R2000 to have plenty space in case the range grows, change to a size that suits you. The result of this formula will be a range. Its size will change every time you put something new in R because of the Counta.
2.- In the validation section place this formula when you record it.
=INDIRECT('Sheet'!$X$1)
This makes the validation read the range based on what x1 says.
This will figure your range,
Sub SelectRng()
Dim Rws As Long, Rng As Range
Rws = Cells(Rows.Count, "A").End(xlUp).Row
Set Rng = Range(Cells(2, "A"), Cells(Rws, "R"))
Rng.Select 'or whatever you want to do with it.
End Sub

Reference another workbook with dynamic worksheet name

I want to reference another workbook and a specific worksheet which is dependent on some cell values.
This equation works
='S:\Down Time[11-Nov_2013_Downtime Tracker.xls]30'!$F$12
but the values 'Nov' and '30' are dynamic-- they depend on the cell values of D13 and E13, respectively.
How can I modify the equation?
Thank you
If you want to do this only by excel formulas, you could modify you formula like this:
=INDIRECT("'S:\Down Time[11-" & A1 & "_2013_Downtime Tracker.xls]" & A2 & "'!$F$12)
In this example it is assumed that the nov-value is in cell A1 and the 30-value is in cell A2. This formula, however, will only work if the referenced workbooks are open. Otherwise the formula would return a #REF! error. Only alternative would be to use VBA.
A little bit late, but here it goes in case someone else is looking for it.
Change the ranges to accommodate your needs.
With VBA:
Sub CallOtherWB()
Dim ThisMonth As String
Dim TheOtherVar As String
ThisMonth = Range("D13").Value
TheOtherVar = Range("E13").Value
With Range("A1")
.Formula = "'S:\Down Time[11-" & ThisMonth & "_2013_Downtime Tracker.xls]" & TheOtherVar & "'!$F$12"
End With
End Sub

Resources