VBA creating formulas referencing a range - vba

After several hours of research, I still can't solve what seems to be a pretty simple issue. I'm new to VBA, so I will be as specific as possible in my question.
I'm working with a DDE link to get stock quotes. I have managed to work out most of the table, but I need a VBA to create a finished formula (i.e., without cell referencing) in order to the DDE link to work properly.
My first code is as follows:
Sub Create_Formulas()
Range("J1").Formula = "=Trade|Strike!" & Range("A1").Value
End Sub
Where J2 is the blank cell and A2 contains the stock ticker. It works fine, but when I try to fill out the rows 2 and bellow, it still uses A1 as a static value.
Sub Create_Formulas()
Dim test As Variant
ticker = Range("A1").Value
'Test to make variable change with each row
'Range("J1:J35").Formula = "=Trade|Strike!" & Range("A1:A35").Value
'not working
Range("J1:J35").Formula = "=Trade|Strike!" & ticker
'not working
End Sub
I couldn't find a way to solve that, and now I'm out of search queries to use, so I'm only opening a new topic after running out of ways to sort it by myself. Sorry if it is too simple.

You are referencing absolute cell adresses here. Like you would do when using $A$1 in a normal excel formula.
What you want to do is:
Dim row as Integer
For row = 1 to 35
Cells(row,10).Formula = "=Trade|Strike!" & Cells(row,1).Value
Next row
This will fill the range J1 to J35 with the formula. Since (row,10) indicates the intersection of row and column 10 (J)

Firstly, in your second set of code, you define a variable "test", but never give it a value.
You assign a value to the variable "ticker", and then never reference it.
Secondly, the value you have assigned to ticker is a static value, and will not change when it is entered in a different row.
Thirdly, I think your issue could be solved with a formula in Excel rather than VBA.
The "INDIRECT" function can be quite useful in situations like this.
Try inserting the formula
=INDIRECT("'Trade|Strike'!"&A1)
into cell A1, then copy down.
Note the ' ' marks around "Trade|Strike". This is Excels syntax for referencing other sheets.

Related

How to apply a Excel formula in VBA macro to find the 2nd to last word

I am quite new to VBA but have been working with Excel a bit. I created a formula that does exactly what I need it to do: find the Nth to last word (mostly 2nd or 3rd to last) in a cell. I think my main issue is how to apply a formula to a range of cells without overwriting the cell and how to use excel formulas in VBA. The Excel formula I use is as follows
=TRIM(LEFT(RIGHT(" "&SUBSTITUTE(TRIM(A1)," ",REPT(" ",60)),180),60))
It might not be the most eloquent way but it works pretty well in Excel. Changing the number 180 to 60 will give last word, 120 2nd to last and so on. But in VBA it gives 1st syntax error and when I get it to run without the arguments and with only TRIM(A1) it overwrites the cell. The code I use is as follows (referencing only A1 to test it):
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT(" " & SUBSTITUTE(TRIM(A1)," " ,REPT(" ",60)),180),60))"
My macro searches and extracts specific data from Sheet1 to Sheet2. Now I would want to apply this (or a similar) formula to the data it extracts to the Sheet2. I have tried a lot of different things from using VBA's own trim to making a completely custom function. None of it seems to work and I think it is down to a misunderstanding on how Excel formulas and VBA play together.
In addition I am trying to find a way to find the only numbers in the cell and trim out everything else. Any help with this would also be appreciated.
EDIT: Sorry guys, I had a mistake in the code I provided, it should have been referring to A1 in both instances.
Double up quotes within a quoted string or use alternatives.
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT("" "" & SUBSTITUTE(TRIM(A20),"" "" ,REPT("" "",60)),180),60))"
'alternative
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT(char(32) & SUBSTITUTE(TRIM(A20), char(32), REPT(char(32),60)),180),60))"
Doubling the quotes as #Jeeped and the commenters wrote is solving your issue with the formula.
As an alternative, you could write a function ("UDF") that returns the n-th word of a string. It is rather easy by using the VBA function split that returns an array of strings. Put the following code in a Module:
Public Function getWord(s As String, ByVal n As Integer) As String
n = n - 1 ' Because Array index will start at 0
Dim arr() As String
arr = Split(s, " ")
If UBound(arr) >= n Then
getWord = arr(n)
End If
End Function
In Excel, you write for example =getWord(A20, 3) as formula

Excel VBA: Insheet function code can not access other cells on sheet

I'm having some issues with an insheet function that I am writing in VBA for Excel. What I eventually am trying to achieve is an excel function which is called from within a cell on your worksheet, that outputs a range of data points underneath the cell from which it is called (like the excel function =BDP() of financial data provider Bloomberg). I cannot specify the output range beforehand because I don't know how many data points it is going to output.
The issue seems to be that excel does not allow you to edit cells on a sheet from within a function, apart from the cell from which the function is called.
I have created a simple program to isolate the problem, for the sake of this question.
The following function, when called from within an excel sheet via =test(10), should produce a list of integers from 1 to 10 underneath the cell from which it is called.
Function test(number As Integer)
For i = 1 To number
Application.Caller.Offset(i, 0) = i
Next i
End Function
The code is very simple, yet nothing happens on the worksheet from which this formula is called (except a #Value error sometimes). I have tried several other specifications of the code, like for instance:
Function test(number As Integer)
Dim tempRange As Range
Set tempRange = Worksheets("Sheet1").Range(Application.Caller.Address)
For i = 1 To number
tempRange.Offset(i, 0) = i
Next i
End Function
Strangely enough, in this last piece of code, the command "debug.print tempRange.address" does print out the address from which the function is called.
The problem seems to be updating values on the worksheet from within an insheet function. Could anybody please give some guidance as to whether it is possible to achieve this via a different method?
Thanks a lot, J
User defined functions are only allowed to alter the values of the cells they are entered into, because Excel's calculation method is built on that assumption.
Methods of bypassing this limitation usually involve scary things like caching the results and locations you want to change and then rewriting them in an after calculate event, whilst taking care of any possible circularity or infinite loops.
The simplest solution is to enter a multi-cell array formula into more cells than you will ever need.
But if you really need to do this I would recommend looking at Govert's Excel DNA which has some array resizer function.
Resizing Excel UDF results
Consider:
Public Function test(number As Integer)
Dim i As Long, ary()
ReDim ary(1 To number, 1 To 1)
For i = 1 To number
ary(i, 1) = i
Next i
test = ary
End Function
Select a block of cells (in this case from C1 through C10), and array enter:
=test(10)
Array formulas must be entered with Ctrl + Shift + Enter rather than just the Enter key.

Referring to OTHER cells in relation to CURRENT cell in loop

I have a data document i'm working on but some things on it are wrong so i need to overwrite specific cells automatically. I'm looking to set up a loop that goes through each cell in column G and if a certain value is present then insert a formula into the cell in the same row but in column J. I've got as far as setting up the loop but I don't know how to put the formula in the new cell and relate it to the current cell. I was thinking R[]C[] formulas may be the way to go but think this becomes confusing when the formula in not straightforward e.g VLOOKUPS with IFs and MATCHES etc...
Sub FindDefects()
Dim RngCl As Range
Dim Rngg As Range
Set Rngg = Sheet1.Range("A1:A6")
For Each RngCl In Rngg.Cells
If RngCl.Value = "TEXT" Then
RngCl.Offset(0,3).FormulaR1C1 = "R[0]C[-1]/R[0]C[3]"
Else
'Nada
End If
Next RngCl
End Sub
I'm not sure really where to go from here, especially how to add in formulas such as:
=IF(LEN(J9)>0,J9*VLOOKUP(M9,Core!A:C,3,FALSE)/VLOOKUP(K9,Core!A:C,3,FALSE),P9)
Instead of R1C1 formulas. Any help on moving forward is appreciated!

User Inserted Rows/Columns Impacting Excel VBA

I am trying to determine how I can have a user insert columns and/or rows without it impacting the rest of the code in the macro.
Defining names for my objects and using r1c1 references in VBA does not seem to help as these inserted columns shift those references and names as well.
Am I missing something that should be completely obvious???
Or is what I am trying to accomplish not possible?
UPDATE: When I name a range in excel (without VBA) everything seems to work fine with inserted columns. However, when I name the range with VBA everything messes up. Here is a sample of some code to work with.
When this below code is run... I am not able to insert columns as my MSGBOX's don't realize the named cell has shifted to the right. HOWEVER, if I were to remove the first line in this code and just name the cell "GanttStartLocation" which is quoted out in the code... this seems to work fine.
WHY DOES THiS NOT WORK WHEN NAMED WITH VBA????
ActiveWorkbook.Names.Add Name:="DEFINENAMETEST", RefersToR1C1:="=Sheet1!R10C14"
Dim rGanttLocation As Range 'Range used to define where the Gantt chart begins
Dim iFirstRowGantt As Integer 'Defines the first row of the Gantt chart based on rGanttLocation
Dim iFirstColumnGantt As Integer 'Defines the first column of the Gantt chart based on rGanttLocation
'Set rGanttLocation = Worksheets(1).Range("GanttStartLocation")
Set rGanttLocation = Worksheets(1).Range("DEFINENAMETEST")
iFirstRowGantt = rGanttLocation.Row
iFirstColumnGantt = rGanttLocation.Column
MsgBox (iFirstRowGantt)
MsgBox (iFirstColumnGantt)
Use a named range for your cells so that addition of rows/columns are less likely to impact your code if rows/columns are added inside the range. For example: if D1-F10 was called testrange, executing the following subroutine will give red background color to the range
Public Sub Test()
Range("testrange").Interior.Color = vbRed
End Sub
If a new row and column are added to this range, and the subroutine is re-executed after replacing vbRed with vbYellow, the entire range (with new column and row) will turn yellow.
Outside of the named range, it's going to take decent amount of work to keep your Macro's generic, from what I understand.

Formula to remain after running macro

I was wondering how I can have a formula stay on column J2:J600. The formula is =R2 and would go all the way down to =R600. I thought I could manually put the formula in but every time I run my macro, the formulas disappear. Is there a way to embed the formula into the column? Thanks.
EDIT
Sub FormatCounsel()
Sheet2.Range("J2").FormulaR1C1 = "=RC[0]"`
Sheet2.Range("J2").AutoFill Destination:=Range("J2:J600"), Type:=xlFillDefault
End Sub
This is what I put in and I'm getting an error.
EDIT 2
Sorry I just realized that I want the formula =R2 in cells J2:J600. Sorry if I caused any confusion.
I see a big red flag in your code: you're using circular referencing! This means that you're saying J2 = J2. In other words, your formula refers to itself for a value, so it calculates to find the value, but to find the value it needs to calculate, etc...
Entering circular referencing should always give you an error when you manually enter circular referencing. However, when using VBA to enter the CR, I was only able to raise an error by setting Application.Calculation to xlCalculationManual, and then calculating the sheet.
You may have just made a typo, and that explains why there's circular referencing in your code, but I figured I'd explain it anyway. :)
R1C1 formulas use relative references to refer to cells. So when you say RC[0], you're saying that you want to use the cell in the same row and the same column. Let's see some examples. In our example, the formula will be in B2.
Dim r As Range
Set r = Range("B2")
r = "=RC" '<~~~ the equivalent to what you used in your code. Refers to B2.
r = "=R[-1]C" '<~~~ Refers to B1 (current row minus 1).
r = "=RC[1]" '<~~~ Refers to C2 (current column plus 1).
r = "=R[1]C[1]" '<~~~ Refers to C3 (current row and current column plus 1).
r = "=R[-1]C[-1]" '<~~~ Refers to A1 (current row and current column minus 1).
Now, as far as entering formulas into cells, it can be done all at once and very easily. Consider the example below:
Sub FormatCounsel()
Sheet2.Range("J2:J600") = "=RC[1]" '<~~ Each cell will refer to the cell to the right.
End Sub
Any time you write something else to those cells or clear them with the macro, you will lose those formulas. You need to find the place in your code where you are overwriting or clearing them, and modify that code. The other option is writing those formulas back to the cells at the end of the macro. You can accomplish this with:
Range("J2").FormulaR1C1 = "=RC[0]"
Range("J2").AutoFill Destination:=Range("J2:J600"), Type:=xlFillDefault