I'm just starting to used named references within my VBA, but have hit a minor problem.
I have a named reference called "SiteCount" that counts the number of sites in a column
=COUNTA(Data!$B:$B)
It is saved as Workbook in scope and works when I use it in a cell as
=SiteCount
I thought I could use this in my code rather than replicate the calculation, however I can not save the value even just as
Sitecount = Range("SiteCount")
I have tried using the worksheet name as well, but I get the same 1004 "Method range of object global failed"
I'm guessing it's something very simple. but I can't figure it out.
Advice is gratefully received :)
Evaluate() should do since it's a formula name not a named range
Dim siteCount as Long
siteCount = Evaluate("SiteCount")
It's not a named range, it's a named formula, so you have to refer to it differently. You can use:
lSiteCount = [SiteCount]
note that the variable name must not be the same as the formula name!
or
SiteCount = Sheets("Data").Evaluate("SiteCount")
or
SiteCount = Application.Evaluate("SiteCount")
If you want to get the values of specific named formulas then:
Sub WhatsInAName()
For Each n In ActiveWorkbook.Names
If n.Name = "SiteCount" Then
MsgBox n.Value & vbCrLf & Evaluate(n.Value)
End If
Next n
End Sub
Related
So I am trying to have a cell reference in my code be an indirect reference. For instance I want to update the value in column B cell "X" where X is defined in cell B1.
Here is the code that I am currently trying but I keep getting an out of range exception. I am very new to VBA so my syntax could just be very far off.
Workbooks("Personal_Finances").Sheets(categoryType).Range("$B($B$1)").Value = ammount
Try,
with Workbooks("Personal_Finances").Sheets(categoryType)
.cells(.Range("B1").Value, "B") = ammount
'alternate
.Range("B" & .Range("B1").Value) = ammount
end with
Here .Range("B1").Value is used for the row reference in .Cells. The alternate is closer to what you were originally attempting.
I've wrapped the working code in a With ... End With block to maintain the parent worksheet reference.
There is no need for $ in a quoted string cell reference unless used in a formula populating multiple cells at once.
def a new variable and assign the value of cell $b$1 to it.
dim temp_row as integer
temp_row.value =Workbooks("Personal_Finances").Sheets("categoryType").Range("B1").Value
Workbooks("Personal_Finances").Sheets(categoryType).Range("$B" & temp_row).Value = amount
or just do the same thing in one line.
Or:
With Workbooks("Personal_Finances").Sheets(categoryType).Range("B1")
.Offset(.Value2 - 1) = ammount
End With
Where the “With ... End With” block references cell B1 of wanted worksheet in wanted workbook and the nested statement offsets it by its value minus one (to reach wanted row)
I'm trying to write a macro that takes a string variable as an input, with the string variable referencing a named range.
Currently what I have is:
Sub SubItems()
Dim M As String
M = "=R[-1]C"
'where M refers to row above, currently it is Manufacturers
Dim g As Range
Set g = Range(" & M & ")
ActiveCell.Value = g(2)
'For Example
End Sub
The problem is with the Set g = Range(" & M & ") syntax
I want the input argument for the Range function to be what M is, and not the literal letter M. Similar to how in C you would do printf('%s', M) for example.
Edit:
Currently how I have the excel sheet setup, is that you select a main item from a drop down menu. Then I want to select the cell below the main item and automatically fill in the rows with sub items. The sub items are stored in a named range that is named after the main item.
Hence I want my macro to automatically read the row above it (Main Item) hence why I have M = "=R[-1]C". Then I want to input that into the range function and that's the problem I'm currently facing.
I hope this clarifies my problem more clearly.
The problem is that your variable M describes a relative reference, and I do not believe you can apply a relative reference to a Range object in the manner you describe. Perhaps you want to attack your problem from a different angle? For instance:
You could use your method but rather set an absolute reference, e.g.
M = "A5"
Debug.Print Range(M).Value
Or alternatively you could specify a relative reference using code such as:
debug.print activecell.Offset(-1,0).Value
String literals are encased in double quotes, so you're essentially referencing a named Range called & M & .
If you're using a string variable, remember that its value is surrounded by quotes as well. So it should just be Range(M), or Range("=R[-1]C"), the two are the same.
Note: =R[-1]C is a very strange name, are you sure you meant this? Make sure you understand the difference between a named range and what's in the range (it looks like a formula)! Perhaps some description on what =R[-1]C is and I can help you more?
What I have understood so far - you have a named range, called M and you want to assign it to a VBA range. If this is the case, this is the code to achieve it:
Sub TestMe()
Dim g As Range
Set g = ActiveSheet.[M]
Debug.Print g.Address
End Sub
I have the following formula:
dim functionString as String
functionString = "IFERROR(AND(MATCH(" & FirstName.Value & ",C2:C1048576, 0)>0, (MATCH(" & LastName.Value & ",B2:B1048576, 0)>0)), MAX(A2:A1048576)+1)"
What I want to be able to do is call it from the VBA code so it would look like.
application.WorksheetFunction(functionString)
I know that I can place it on the worksheet at some cell that's never going to be used: IE:
Activesheet.range("ZZ1000").formula = "="& functionString
and then reference that cell without worrying whether the program would inadvertently crash; but is there a way to do such a formula from VBA directly?
Basically I'm looking to see whether FirstName.Value and LastName.Value (which are defined elsewhere in the code) together are in the worksheet in column B and column C. As I'm writing this, I realized I need to make sure that they are both in the same row as well and not in different rows.
You could try Application.Evaluate(functionString) but depending on complexity it may be better to use VBA functions instead of WorksheetFunctions.
The Application.Match function will return an error type if the value is not found in the range/array, so we Dim first, last as variant type to allow for this (without raising an error).
Dim first, last
' find the row where FirstName.Value appears in column C
first = Application.Match(FirstName.Value, Columns(3), False))
' find the row where LastName.Value appears in column B
last = Application.Match(LastName.Value, Columns(2), False))
If Not IsError(first) And Not IsError(last) Then
If first = last Then
' match was found in both columns and on same row
' do something else...
End If
End If
I created the following function using Excel 2010. It seem to work only when i use the function in the same sheet the array was created (sheet2) and if a value is typed in the function e.g.: =KeyExists(1443). I need to use this function in another sheet within the workbook and needs to be a cell reference. Stumped on why its not working.
Option Explicit
Function KeyExists(k)
Dim d As Object
Dim c As Variant
Dim i As Long
Dim lr As Long
Dim msg As String
Set d = CreateObject("Scripting.Dictionary")
lr = WorkSheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
c = Range("A2:A" & lr)
For i = 1 To UBound(c, 1)
d(c(i, 1)) = 1
Next i
If d.exists(k) Then
msg = "key exists"
Else
msg = "key does not exist"
End If KeyExists = msg
End Function
'parts of the code derived from:
'hiker95, 07/26/2012
'http://www.mrexcel.com/forum/showthread.php?649576-Extract-unique-values-from-one-column-using-VBA
Change it from Sheet2 to the active sheet:
lr = ActiveWorkbook.ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
If the unique Keys are only in Sheet2 Column A2 and onward... You can create a dynamic named Range and reference it anywhere in the Workbook.
Say you have data:
Create a dynamic named range Keys with =OFFSET(Sheet2!$A$1,1,0,COUNTA(Sheet2!$A:$A)-1,1).
Then say you want to check for values in C4, use formula below:
=IF(ISNUMBER(IFERROR(MATCH(C4,Keys,0),"")),"key exists","key does not exists")
There is no need to use VBA for what you want to achieve your goal. e.g.
I agree with commenters regarding the Dictionary. In my opinion, it would be much easier to do without it. I also think other ways would be vastly quicker, depending on how much data you have.
Example:
Function KeyExists(k As Range) As String
Dim ws As Worksheet
Dim c As Range, i As Long
' Set ws to the worksheet to which k belongs.
' This avoids activeworksheet and also allows for
' qualified references to other sheets if necessary.
ws = k.Worksheet
Set c = ws.Range("A2:A" & ws.Cells(Rows.Count, 1).End(xlUp).Row)
On Error Resume Next
i = Application.WorksheetFunction.Match(k.Value, c, 0)
On Error GoTo 0
If i <> 0 Then
KeyExists = "Key exists"
Else
KeyExists = "Key does not exist"
End If
End Function
Using MATCH will most likely be a lot faster than adding every entry of data into a Dictionary.
A case where you might argue using Dictionary is marginally better, is if you want to make sure the value is unique. But even then, you'd have to use round-about logic to deal with the what-if of encountering duplicate keys and what to do at that point.
Your question does not really specifiy whether or not you need to perform this check or not, or what to do if duplicates are found, so it's hard to advise on it. In any case, if you opt for this method I would recommend creating a separate procedure that declares and builds the dictionary and run it on Worksheet_Open or something like that, leaving you to use a very short function for querying the existence of a key. This circumvents you having to build the dictionary every time the formula runs and will most likely be faster (and require more coding) than my solution.
I have a small script in Excel/VB that I'm trying to get working. All I want to do is select a dynamic range of data to copy but I can't seem to find any help/code on how to get the grid data (like A11).
Here is code I have from macro recording that selects the range of data:
Range("D291:D380").Select
I was hoping I could just do Range(Current).Select or something but that doesn't work.
How do I get the current cell using VBA?
Have you tried:
For one cell:
ActiveCell.Select
For multiple selected cells:
Selection.Range
For example:
Dim rng As Range
Set rng = Range(Selection.Address)
This may not help answer your question directly but is something I have found useful when trying to work with dynamic ranges that may help you out.
Suppose in your worksheet you have the numbers 100 to 108 in cells A1:C3:
A B C
1 100 101 102
2 103 104 105
3 106 107 108
Then to select all the cells you can use the CurrentRegion property:
Sub SelectRange()
Dim dynamicRange As Range
Set dynamicRange = Range("A1").CurrentRegion
End Sub
The advantage of this is that if you add new rows or columns to your block of numbers (e.g. 109, 110, 111) then the CurrentRegion will always reference the enlarged range (in this case A1:C4).
I have used CurrentRegion quite a bit in my VBA code and find it is most useful when working with dynmacially sized ranges. Also it avoids having to hard code ranges in your code.
As a final note, in my code you will see that I used A1 as the reference cell for CurrentRegion. It will also work no matter which cell you reference (try: replacing A1 with B2 for example). The reason is that CurrentRegion will select all contiguous cells based on the reference cell.
The keyword "Selection" is already a vba Range object so you can use it directly, and you don't have to select cells to copy, for example you can be on Sheet1 and issue these commands:
ThisWorkbook.worksheets("sheet2").Range("namedRange_or_address").Copy
ThisWorkbook.worksheets("sheet1").Range("namedRange_or_address").Paste
If it is a multiple selection you should use the Area object in a for loop:
Dim a as Range
For Each a in ActiveSheet.Selection.Areas
a.Copy
ThisWorkbook.worksheets("sheet2").Range("A1").Paste
Next
Regards
Thomas
If you're trying to grab a range with a dynamically generated string, then you just have to build the string like this:
Range(firstcol & firstrow & ":" & secondcol & secondrow).Select
I realize this doesn't directly apply from the title of the question, However some ways to deal with a variable range could be to select the range each time the code runs -- especially if you are interested in a user-selected range. If you are interested in that option, you can use the Application.InputBox (official documentation page here). One of the optional variables is 'type'. If the type is set equal to 8, the InputBox also has an excel-style range selection option. An example of how to use it in code would be:
Dim rng as Range
Set rng = Application.InputBox(Prompt:= "Please select a range", Type:=8)
Note:
If you assign the InputBox value to a none-range variable (without the Set keyword), instead of the ranges, the values from the ranges will be assigned, as in the code below (although selecting multiple ranges in this situation may require the values to be assigned to a variant):
Dim str as String
str = Application.InputBox(Prompt:= "Please select a range", Type:=8)
Try this
Dim app As Excel.Application = Nothing
Dim Active_Cell As Excel.Range = Nothing
Try
app = CType(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
Active_Cell = app.ActiveCell
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
' .address will return the cell reference :)