Set an Array with a variable name VBA - vba

I am trying to use VBA to set an array based on a cell value in my workbook. I have an Array set on my data called THREEMO. For this month the value is Aug. I want to add a Sheet named Aug and then set an array for Columns B:C and name them Aug as well. I was able to add the sheet and name it but the array is not letting me use the variable to name the array. Here is what I have so far:
Dim WS As Worksheet
Set WS = Sheets.Add(After:=Sheets(Worksheets.Count))
WS.Name = Range("THREEMO")
Dim stNewTab As String
stNewTab = Range("THREEMO")
'Set Arrays
Columns("B:C").Select
ActiveWorkbook.Names.Add Name:=Range("THREEMO"), RefersToR1C1:="=Range("THREEMO")!C2:C3"
I am getting the error on the "'Set Arrays" section. This is what it looks like when I record the macro, so I am just having trouble setting up RefersToR1C1 with the variable for the month:
ActiveWorkbook.Names.Add Name:="AUG", RefersToR1C1:="=Aug!C5:C6"

Change
ActiveWorkbook.Names.Add Name:=Range("THREEMO"), RefersToR1C1:="=Range("THREEMO")!C2:C3"
to
ActiveWorkbook.Names.Add Name:=stNewTab, _
RefersToR1C1:="=" & stNewTab & "!C2:C3"
Note/Explanation:
Range("THREEMO") within quotes is considered as a string. Keep it outside the quotes. Better still use the variable stNewTab
The line
ActiveWorkbook.Names.Add Name:="AUG", RefersToR1C1:="=Aug!C5:C6"
can also be written as
ActiveWorkbook.Names.Add Name:="AUG", RefersToR1C1:="=" & "Aug" & "!C5:C6"
Now all you have to do is replace "Aug" with the variable.

Another option, you can set up the Range like this:
Dim Rng As range
Set Rng = WS.Range("C5:C6")
And then, you can use the Names.Add command a little different
ActiveWorkbook.Names.Add Name:=stNewTab, RefersTo:=Rng

Related

How to put an excel formula to a dynamic range of cells using VBA?

I am new to VBA and am using the following snippet to populate a range of cells with a vlookup function:
With wbk1.Sheets("classes")
.Range("AA2:AA" & .Range("C" & .Rows.Count).End(xlUp).Row).Formula = "=VLOOKUP(C2,lookup!$A$2:$B$14,2,FALSE)" 'Actual vlookup
In order to make this dynamic, I want to replace the .Range("AA2:AA" & .Range("C" & .Rows.Count) part with a dynamic reference (in my case the first empty column in the same sheet).
First, I find the first empty column with this one-liner:
first_empty_column = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
However, when I do
With wbk1.Sheets("classes")
.Range(ws.Cells(1, first_empty_column) & .Range("C" & .Rows.Count).End(xlUp).Row).Formula = "=VLOOKUP(C2,lookup!$A$2:$B$14,2,FALSE)" 'Actual vlookup
I get "Runtime Error '1004': Application-defined an object-defined error.
What is the syntax to define hard-coded ranges dynamically in this context?
You need to use the following Range reference logic:
'PSEUDO-CODE
.Range(LeftTopCell, RightBottomCell)
where both LeftTopCell and RightBottomCell can be set with any valid range reference.
Moreover, you can not combine reference to range from two different sheets. You are referencing both ws and Sheets("classes") in single range reference.
Try with this:
With wbk1.Sheets("classes")
.Range(.Cells(1, first_empty_column), _
.Cells(.Range("C" & .Rows.Count).End(xlUp).Row, first_empty_column)).Formula = "=VLOOKUP(C2,lookup!$A$2:$B$14,2,FALSE)" 'Actual vlookup
End With

Excel VBA - Using the Split function but with multiple/variable strings

I have a column with dozens/hundreds of different names, some listed multiple times. Each name is formatted as firstname.lastname. I need to split these up to be correctly listed as firstname lastname. Using the split function, usually the first parameter is the string you need to split.
I have used this before with an array of items to split, but I have always had to list each item in the array. This, of course, is not possible with hundreds of different names.
I have searched, but every answer I find always uses an array, or is discussing how to split into multiple columns.
How can it be written so that the code could loop through the entire column (B, in this case) and split every name, while keeping everything in the one column?
The code will be something like:
nameSplit = Split(all_names_in_column_B, ".")
Select the column, press control and F to bring up Find and Replace, Find "." and replace enter a space (by pushing the spacebar once). Does assume you don't have other text within the cells containing periods.
You could do the same thing in VBA.
Sub TEST()
ActiveSheet.Columns("A").Replace _
What:=".", Replacement:=" ", _
SearchOrder:=xlByRows, MatchCase:=False
End Sub
The code to do this looks like this
Public Sub SplitTest()
Dim ws As Worksheet 'Declare a worksheet variable
Dim sheetName As String: sheetName = "Sheet1" 'Provide the name of the sheet where the data is located
Set ws = ActiveWorkbook.Sheets(sheetName) 'Assign it to the worksheet variable
Dim inputRng As Range 'Declare a range variable
Dim rangeName As String: rangeName = "B1:B5" 'Assign the range location using whatever method you like to select your range
Set inputRng = ws.Range(rangeName) 'Assign the range to the range variable
Dim splitStringArray() As String 'Declare a variable length array of strings to hold the result of the split
Const FirstName = 0 'FirstName is element 0 of splitStringArray
Const LastName = 1 'LastName is element 1 of splitStringArray
Dim enumRng As Range 'Declare a range variable to be used as an enumerator
For Each enumRng In inputRng 'Loop through the range one cell at a time
splitStringArray = Split(enumRng, ".") 'Split the value located in the cell
enumRng.Value2 = splitStringArray (FirstName) & " " & splitStringArray (LastName) 'Overwrite the value in the current cell with the First and Last Names
'separeated by a space, this could be anything
Next enumRng
End Sub

VBA Worksheet Sub Create Named Range in Another Worksheet

I have a private sub that needs to create named ranges within another worksheet. It needs to stay a worksheet function, as it is a Worksheet_Change sub. I have successfully been able to set a range variable equal to a range on another sheet with this line:
Set rng2 = Sheets("Lists").Range(Sheets("Lists").Cells(2, Col), Sheets("Lists").Cells(Unique, Col))
However, when I put rng2 into the other portion of my code, it simply refers to the correct range within the Active Sheet.
Here is what I have tried:
ActiveWorkbook.Names.Add Name:="Level" & Col, RefersTo:= _
"= " & Sheets("Lists").Range(Sheets("Lists").Cells(2, Col), Sheets("Lists").Cells(Unique, Col)).Address & ""
and:
ActiveWorkbook.Names.Add Name:="Level" & Col, RefersTo:= _
"=" & rng2.Address & ""
The bottom function works when it is within a module stored inside the workbook as a whole, but again, does not work within a worksheet sub.
I have also tried Sheets("Lists").rng2.Address in the bottom attempt.
To have the address include the sheet's name, you have to set the external parameter:
rng2.address(external:=True)
Your RefersTo string needs to be something like "=Lists!A1". So all it's missing is the reference to the lists worksheet.
Try something like this:
Dim wsLists As Worksheet
Set wsLists = ThisWorkbook.Worksheets("Lists")
With wsLists
Set rng2 = .Range(.Cells(2, Col), .Cells(Unique, Col))
ThisWorkbook.Names.Add Name:="Level" & Col, RefersTo:="=" & rng2.Address(external:=True)
End With

How to add a Formula To Cell using VBA [duplicate]

This question already has answers here:
How do I put double quotes in a string in vba?
(5 answers)
Closed 1 year ago.
I am attempting to write some VBA which will add header text to 3 cells then fill a formula all the way down to the last row. I have written the below, which writes the headers no problems, but when it get's to my first .Formula it throws a
Application Defined or Object Defined error
What needs to be altered so that this macro will execute successfully? (The formulas were pulled directly from the formula in the cell, so I know they are valid formulas at least on the "front-end")
Function Gre()
Range("E2").Select
ActiveCell.FormulaR1C1 = "Under"
Range("F2").Select
ActiveCell.FormulaR1C1 = "Over"
Range("G2").Select
ActiveCell.FormulaR1C1 = "Result"
With Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(C2<B2,B2-C2,"")"
End With
With Range("F2:F" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(C2>B2,C2-B2,0)"
End With
With Range("G2:G" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=IF(F2>0,'Issue',"")"
End With
End Function
The problem is likely that you are escaping the quotes with the formula.
What you need is:
.Formula = "=IF(C2>B2,B2-C2,"""")"
for the first one, for example. The other quotes need to be doubled as well.
As a side-note, it would also be best to specify the sheet you are working on with something like:
Dim ws as worksheet
Set ws = Sheets("mySheet")
ws.Range("E2").FormulaR1C1 = "Under"
etc.
If you don't do this, you can sometimes have errors happen while running the code.
As suggested by OpiesDad, to minimize ambiguity, avoid ActiveCell and the like.
Using Select will also slow down performance a lot compared to assigning to cells directly.
I'm pretty sure you need to escape quotes in Excel formulas inside of VBA by doubling the quotes, so a normal empty string becomes """". You also have Issue in single quotes in a formula, which I'm pretty sure will error in Excel; that should be in escaped double quotes as well.
I'm having a hard time figuring out what Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) actually does, but it sounds like you want to select E2 to the last used row of the sheet. Avoid Rows.Count or just generally referring to the rows of a sheet, as that will go to row 10^31. Use Worksheet.UsedRange to get the range from the first row and column with content to the last row and column with content. This also includes empty strings and can be a bit tricky sometimes, but is usually better than dealing with thousands of extra rows.
Also,
You don't need to use With if your only enclosing one statement, although it won't cause any problems.
I would not mix use of Range.Formula and Range.FormulaR1C1 unless you have a reason to.
Function Gre()
Dim ws as Worksheet
Set ws = ActiveSheet
Dim used as Range
Set used = ws.UsedRange
Dim lastRow as Integer
lastRow = used.Row + used.Rows.Count - 1
ws.Range("E2").Formula = "Under"
ws.Range("F2").Formula = "Over"
ws.Range("G2").Formula = "Result"
ws.Range("E2:E" & lastRow).Formula = "IF(C2<B2, C2-B2, """")"
ws.Range("F2:F" & lastRow).Formula = "IF(C2<B2, C2-B2, 0)"
ws.Range("G2:G" & lastRow).Formula = "IF(F2>0, ""Issue"", """")"
End Function
The first issue is the selecting of cells. This requires the macro to select the cell, then determine the cell address. If you need to actually select a cell, use Application.ScreenUpdating = False. Then the macro doesn't have to show the cursor selection of a cell. Dropping the select and incorporating the range into the formula assignment code line like below will gain some speed/efficiency.
Range("E2").FormulaR1C1 = "Under"
Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) is the code version of selecting the last cell in a blank column (row 1048576), then using the keystroke of ctrl and the up key to determine the lowest/last used cell. This gets you a row count of 1 every time since the column is blank. Since you're looking for the last row. It may be faster to count down from the top. My favorite method for this is a loop. Increment a variable within a loop, while looking for the last row. Then, the variable can be used instead of your bottom up strategy.
t = 0
Do Until Range("C2").Offset(t, 0).Value = ""
t = t + 1
Loop
With Range("E2:E" & t)
.Formula = "=IF(C2<B2,B2-C2,"""")"
End With`
Just like TSQL, quote characters need their own quote characters.
.Formula = "=IF(C2<B2,B2-C2,"""")"
The Range Fillup VBA function can be utilized in this case to fill all cells from the bottom with a common formula, accounting for Excel Formula Reference Relativity. The code below starts with the range that we got from the loop counter. Next, we set a variable equal to the total rows in Excel minus the row corresponding to the counter row. Then, we resize the original region by the necessary rows and use the FillDown function to copy the first formula down.
Here's the resulting code. This will fill the range starting from the last row in Excel.
Sub Gre()
Range("E2").FormulaR1C1 = "Under"
Range("F2").FormulaR1C1 = "Over"
Range("G2").FormulaR1C1 = "Result"
Do While Range("e2").Offset(t, 0).Value <> ""
t = t + 1
Loop
Range("E2").Offset(t, 0).Formula = "=IF(C2<B2,B2-C2,"""")"
r1 = Range("e2").EntireColumn.Rows.Count
r2 = Range("E2").Offset(t, 0).Row
Range("E2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
Range("F2").Offset(t, 0).Formula = "=IF(C2>B2,C2-B2,0)"
Range("F2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
Range("G2").Offset(t, 0).Formula = "=IF(F2>0,""Issue"","""")"
Range("G2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
End Sub
As well as using double quotes you may need to use 0 in the first two formula otherwise they may evaluate to empty strings. This may give unexpected results for the last formula i.e. incorrectly return "Issue".
If you do not have blank columns between your data and the 3 new columns you can use CurrentRegion to determine the number of rows:
Range("E2:E" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2'<'B2,B2-C2,0)"
Range("F2:F" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2>B2,C2-B2,0)"
Range("G2:G" & Cells.CurrentRegion.Rows.Count).Formula = if(F2>0,""Issue"","""")"
Please try the following sample hope it will help you to wright formula in VBA
Sub NewEntry()
Dim last_row As Integer
Dim sht1 As Worksheet
Dim StockName As String
Set sht1 = Worksheets("FNO MW")
last_row = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'MsgBox last_row
StockName = sht1.Cells(last_row, 1).Value
sht1.Cells(last_row, 1).Formula = "=RTD(""pi.rtdserver"", ,"" " & StockName & " "", ""TradingSymbol"")"
End Sub

Named range in conditional formatting formula

I have code like below. And I would like to set named ranges (cells) instead of ranges (cells) H$7 and $G$7. Because if for example I add new column before these cells and recover macro with this code it does not work correctly. Have you got any idea? Thanks in advance
With Range(SomeRange).FormatConditions _
.Add(xlExpression, xlFormula, "=((H$7<=$G$7)*((H$7+7)>$G$7))")
With .Interior
.Color = RGB(197, 217, 241)
End With
End With
Just type the name of a named range in the formula, nothing special as long as the named range exists. If I name H7 "B" and G7 "A" then this works for me...
Sub Test()
'Range
Dim R As Range
Set R = Range("A1")
R.FormatConditions.Delete
'Formula
Dim F As String
F = "=((B<=A)*((B+7)>A))"
'Condition
Dim Cond As FormatCondition
Set Cond = R.FormatConditions.Add(xlExpression, xlFormula, F)
Cond.Interior
Cond.Color = RGB(197, 217, 241)
End Sub
Note though, with the formula argument of 'FormatConditions.Add', everything within the double quotes gets evaluated exactly as if typed within a cell. The argument is passed as a string and interpreted as a literal string value. So you can test your formula string by copying and pasting it to a cell and it should work the same (return 1 or 0), modify it in the cell, and copy and past back.
You don't have to create/set the names problematically, but if you want to, then I'd probably use the workbooks collection unless you repeat the same name on multiple sheets, then use the worksheet collection.
About named ranges...
The Object (Name)
The Collection (Names)
Setting Referencing
Try getting the address of the named ranges and concatenating them in your formula string.
Eg.
Adr1= range("namedrange1"). Address
Adr2= range("namedrange2"). Address
With Range(SomeRange).FormatConditions _
.Add(xlExpression, xlFormula, "=((" & adr1 & "<=" & ad2 & ")*((" & adr1 & "+7)>" & adr2 & "))")