Okay, I have a basic understanding of how to record macros in VBA.
I have a bunch of cells, each referencing cells on other sheets. (Ex: =R!$A$1). These cells don't match the destination cells (for example, D3 on the primary sheet contains =R!$A$1, and the next entry is F3 referencing =R!$A$4).
Using VBA, I tried replacing the first instance with =IF(R!$A$1="", "TBA", R!$A$1). This recorded and worked for the cell in question, but when I moved to F3 and ran the macro, it replaced the cell with the exact same formula. How do I get VBA to take the existing text in the cell as replacement text, instead of blindly copying the first example?
My first thought was ActiveCell.R1C1 = "=IF( ActiveCell.R1C1 = "", "TBA", ActiveCell.R1C1) but that failed to compile.
Thanks!
Try something like this (if I understand what it is you're trying to do...)
Sub Test()
Dim frm As String
If ActiveCell.HasFormula Then 'formula in cell?
frm = ActiveCell.Formula 'read the existing formula
frm = Right(frm, Len(frm) - 1) 'remove the `=`
ActiveCell.Formula = _
"=IF(" & frm & "="""",""TBA""," & frm & ")" 'set new formula
End If
End Sub
Related
I would like to limit all of the formulas in a selected range of cells with an additional if statement.
Is it doable with the use of the VBA?
Let's say:
cell A1 contains =sum(B1;C1) but it can be any formula that a selected cell contains
after applying macro updated formula would be =if(D100>0;sum(B1;C1);0)
=if(D100>0;any formula in a cell ;0)
You can achieve this by using code like this:
Sub ModifyFormulas()
Dim cl As Range, formulas_cells As Range
Const template = "=if(D100>0,#,0)" '# will be replaced by old formula without '='
On Error Resume Next ' handle an error if there are no formulas in the range
Set formulas_cells = Range("A1:A10").SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not formulas_cells Is Nothing Then
For Each cl In formulas_cells
cl.Formula = Replace(template, "#", Mid(cl.Formula, 2))
Next
End If
End Sub
Without vba, I use the following method:
edit / replace the "=" with "xyxy" - this stops excel recalculating
then edit / replace "sum" with "if(D100>0;sum"
then edit / replace ")" with ");0)"
lastly replace "xyxy" with "="
and then it all works, done this often with my sheets when I have to change some calculations...
I have a sheet called Line Item Summary with cell E7 that has the formula ='Costing Sheet'!I75. Instead of having the formula reference Costing Sheet I would like to replace it with the sheet that is being worked on (so the active sheet) .
The active sheet name may change as copies are made but the cell I75 where there data is referencing will always be the same.
I have tried the following code but I get "Run-time error '9':Subscript out of range".
Sub Connect()
Sheets("Line Item Summary").Range("E7").Formula = "='ActiveSheet'!I75"
End Sub
I tried to explain this as best I can but please let me know if it needs clarification. Thanks!
Remove the activesheet from the quotes otherwise it is treated as a literal string.
Sub Connect()
Sheets("Line Item Summary").Range("E7").Formula = "='" & ActiveSheet.name & "'!I75"
End Sub
But your formula will change - is that what you intend?
I have this recorded macro that I want to convert to plain VBA macro code and copy the formula from AE2 to lastrow.
"=VLOOKUP(RC[-22],'[test.xlsx]Sheet3'!C5:C6,2,0)" ' this is from another workbook
Trying to convert to VBA.
dim wbSLW as workbook
dim wbSLWDir as String
wbSLWDir = "C\Documents\test.xlsx" 'this is not the constant directory or file name
set wbSLW = workbooks.open(wbSLWDir)
ThisWorkbook.Activate
With Thisworkbook.Sheets(1)
.Range("AE2") = "=VLOOKUP(I2," & wbSLW & "!E:F,2,0)" ' error line
end with
When I've converted it, it returns Object does not support this property or method.
Change your settings so that it does not use R1C1 format by going to (Excel 2010) Settings / Formulas and then unchecking the R1C1 reference style. Rerecord your macro and then edit it. You should not have any "RC" references, but if you do then change all references that have "RC" in them to the the same style as in "I2".
Cleaned recorded code :
With ActiveSheet.Range("AE2")
.FormulaR1C1 = "=VLOOKUP(RC[-22],Temp!C[-30]:C[-29],2,0)"
.AutoFill Destination:=Range("AE2:AE182"), Type:=xlFillDefault
End With 'ActiveSheet
RC[-22] refers to a cell that is 22 columns before the cell in which you have the formula here AE2 is the initial cell, so RC[-22]=I2
C[-30] and C[-29] refers respectively to columns that are 30 and 29 columns before the cell in which you have the formula
here AE2, so C[-30]=A and C[-29]=B
Changed formula :
Sheets(1).Range(perNum & 2).Formula = "=VLOOKUP(I2,Temp!A:B,2,0)"
or without converting the formula :
Sheets(1).Range(perNum & 2).FormulaR1C1 = "=VLOOKUP(RC[-22],Temp!C[-30]:C[-29],2,0)"
Assuming that Active Sheet name is Sheet1
ActiveCell.Value = Application.WorksheetFunction.VLookup(Sheets("Sheet1").Range("I2"), Sheets("Temp").Range("A:B"), 2, 0)
If i understood correctly, you want to replace name of the workbook in below line in vba code :
=VLOOKUP(RC[-22],'[**test.xlsx**]Sheet3'!C5:C6,2,0)
Simplest way to do that without changing any other code is :
=VLOOKUP(RC[-22],'[**" & wbSLW.Name & "**]Sheet3'!C5:C6,2,0)
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
I've written a macro in VBA that simply fills in a given cell's value from another cell in that sheet. I do this for lots of cells in the sheet, and I'm doing it like so:
Range("B3").Value = Range("B200")
Range("B4").Value = Range("B201")
'etc.
Now, I am often adding values by inserting new rows, so I might insert a new row
between B200 and B201, which will break the macro because it doesn't autoupdate when
I insert the new row.
How can I code the macro so it autoupdates the cell references when I insert new rows or columns?
My suggestion would be to make sure the ROW you want to retrieve values from has a unique value in it that you can .FIND anytime you want, then grab your values from column B of that found cell's row. So right now you want to get a value in B200 and A200 always has the text in it: "Final Total" and that is unique.
Dim MyRNG As Range
Set MyRNG = Range("A:A").Find("Final Total", LookIn:=xlValues, LookAt:=xlWhole)
Range("B3").Value = Range("B" & MyRNG.Row)
Range("B4").Value = Range("B" & MyRNG.Row + 1)
This is not an answer but an alternative.
Naming your range is the way to go as Shiin suggested but then if you have 500 cells then like I mentioned earlier, naming 500 cells and using them in your code can be very painful. The alternative is to use smart code. Let's take an example
Let's say you have a code like this
Sub Sample()
Range("B3").Value = Range("B200")
Range("B4").Value = Range("B201")
Range("B5").Value = Range("B201")
' And
' So On
' till
Range("B500").Value = Range("B697")
End Sub
The best way to write this code is like this
Sub Sample()
Dim i As Long
For i = 200 To 697
Range("B" & i - 197).Value = Range("B" & i)
Next i
End Sub
and say if you insert a line at say row 300 then simply break the above code in two parts
Sub Sample()
Dim i As Long
For i = 200 To 299
Range("B" & i - 197).Value = Range("B" & i)
Next i
For i = 301 To 698
Range("B" & i - 197).Value = Range("B" & i)
Next i
End Sub
So every time you insert a row, simply break the for loop into an extra part. This looks tedious but is much better than naming 500 cells and using them in your code.
If you are planning to use the macro only once (i.e for 1 time use) then read ahead.
If you are worried that when the user inserts the row then the cells are not updated then you can instead of assigning a value, assign a formula.
For example
Range("B3").Formula = "=B200"
This will put a formula =B200 in cell B3. So next time when you insert a row so that the 200th row moves it's position, you will notice that the formula automatically gets updated in cell B3
HTH
Try giving a name to the range. If you refer to the range by name Excel searches for it and retrieves the rows that defines it. Range names update their definition when new rows are added.
Adding to the above, i think this tutorial illustrates my point:
http://www.homeandlearn.co.uk/excel2007/excel2007s7p6.html this is how to define the name of the range.
This tutorial explains how to use it on macros and vba:
http://excel.tips.net/T003106_Using_Named_Ranges_in_a_Macro.html
I hope this helps :D