I'm having troubling referring to a Dynamic Name Range in VBA.
My ranges are defined as
=OFFSET(Sheet!$B$2,0,0,COUNTA(Sheet!$B:$B)-1,1)
My code should search one range for all entries in another range, the intention being that any missing entries will be added. So far I have
Sub UpdateSummary()
Dim Cell As Range
Dim rngF As Range
Set rngF = Nothing
' Step through each cell in data range
For Each Cell In Worksheets("Aspect").Range("A_Date")
' search Summary range for current cell value
Set rngF = Worksheets("Summary").Range("Sum_Date").Find(Cell.Value) // Does not work
If rngF Is Nothing Then
' Add date to Summary
End If
Set rngF = Nothing
Next Cell
End Sub
The For loop seems to work ok. However, using the .Find method is giving me an error message.
Application-defined or object-defined error
It does work if I replace the named range with a specific range ($B$2:$B$5000), so it seems to be down to how the named range is being passed.
Any ideas would be appreciated.
Thanks.
The error is almost definitely because Excel can't find a named range Sum_Date that refers to a range on a worksheet named Summary. The most common causes are
Sum_Date refers to a sheet other than Summary. Check the RefersTo property of Sum_Date and make sure nothing is misspelled.
There is not a named range Sum_Date, that is, it's misspelled in the VBA code. Check the spelling of the named range in the Name Manager.
There is an error in the RefersTo formula of Sum_Date. It sounds like you already verified that this isn't the case.
I've had the a similar if not the same problem & here's how I solved it:
I first realized that the method I used to create my named range, using the Name Manager, my named range had a scope of Workbook. This is important because, it doesn't belong to the worksheet, & therefore will not be found there.
So, Worksheets("Summary").Range("Sum_Date") would not work for me.
Since my range belonged to the workbook, the way I was able to find is to use ActiveWorkbook.Names("Sum_Date")
For me I used it to remove the formula from named range that I am using in many places. The huge advantage is that named range is updated only once instead of the formula being called for every cell location that ranged is called. Huge time delay difference!
Public last_Selection As String
Private Sub Worksheet_Change(ByVal Target As Range)
'excel data change detection
If Range(last_Selection).Column = 2 Then
'Disable events, so this only executes once
Application.EnableEvents = False
'This can be done with a complex formula in a cell,
'but this is easily understood
Range("B1").End(xlDown).Select
ActiveWorkbook.Names("last_Entry").Value = ActiveCell.Row
'Re-enable so this routine will execute on the next change
Application.EnableEvents = True
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'constantly store the last cell to know which one was previously edited
last_Selection = Target.Address
End Sub
I know this is a very old thread, but I had the same issue today and I was looking for solution for quite a long time. So maybe this will help someone.
The named "range" defined by the =OFFSET(...) formula is actually a named FORMULA, so in VBA you have to evaluate it first to get the range. E.g.:
Set rgNamedRange = Worksheets("Summary").Evaluate("Sum_Date")
Credits to a guy named "shg" from mrexcel.com, who got me on right track. :)
I have been experimenting with this for a few days and eventually I came up with the following. It may not be the most efficient but it did work for me!
The named range of "OhDear" was set up in the normal way
Dim vItem As Variant
Set vItem = Names("OhDear")
Debug.Print vItem.Name
Worth a try don't you think!
This does not work if instead of using a variant you use something like: Dim Nm as Name: Set Nm = Names("OhDear"). Any variations using 'Nm' failed!!!
Related
I have this code which is causing a mismatch error and I can't figure out why I had it working sort of before with the mismatch error and in an attempt to fix it I can't get it back to working. The values in the merge sheet are all numeric. Basically what I was trying to do was when a value is entered into a cell there would be a VLookup would be executed to input a value into the adjacent cell and once I get this working, more cells in the same row. If any of you are itching to fix something just let me know!
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim LooupValue As String
Dim sfx As Long
Set KeyCells = Columns(1)
LooupValue = ActiveCell.Value
sfx = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
Range(Target.Address).Offset(0, 1).Value = sfx
End If
End Sub
Edit: Thanks to #Marcucciboy2, #MathieuGuindon, and #BigBen for their successful help, I have done some more research and posted what solved my issue down below.
Dim sfx As Long
sfx = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
If the vlookup yields xlErrNA i.e. #N/A, then VBA can't coerce its result into a Long, and you get exactly that: a type mismatch error - because xlErrNA is an Error value, which can't be implicitly converted to a String, a Long, or anything. The only type that can contain this data, is a Variant.
Dim result As Variant
result = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
Dim sfx As Long
If Not IsError(result) Then
sfx = CLng(result)
Else
'lookup yielded no match
End If
Also, it looks like this is off-by-one:
LooupValue = ActiveCell.Value
The ActiveCell likely isn't the same cell as Target, which is the cell that was modified. You probably need this instead:
LookupValue = Target.Value
I'd also recommend making unqualified Range (same with Rows, Colomns, Names, and Cells) calls explicitly qualified - because that exact same code behaves differently depending on where it's written in. By qualifying them with Me, you're making your code more explicit. Code that says what it does, and does what it says, is always better code.
Worksheets("Merge") is a smell: if the sheet exists in ThisWorkbook at compile-time, give it a code name (i.e. set its (Name) property) and use that identifier directly:
result = Application.VLookup(LooupValue, MergeSheet.Range("D:BD"), 2, False)
If the sheet only exists at run-time (e.g. it's in a workbook that was opened by the macro), then you should have a reference to that workbook near where you opened that file, e.g. Set book = Application.Workbooks.Open(path) - use that reference to qualify the Worksheets member call, instead of implicitly referring to ActiveWorkbook.
The lookup range D:DB is excessive when you're only looking for the value in column E. If that hard-coded 2 is there to stay, I'd make the lookup range be D:E.
I would also nest the value setting within the "If" that checks for intersection; otherwise, every time you change the worksheet it does an unnecessary vlookup in the background.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("A:A")) Is Nothing Then
Target.Offset(0, 1).value = Application.VLookup(Target.value, Worksheets("Merge").Range("D:BD"), 2, False)
End If
End Sub
I figured out what the last problem was... The lookup column was, for some reason from the previous document editor, formatted as text. The reason why only some lookup values were working was because even after I formatted the entire column to numbers, the said values were reformatted as numbers only after I had edited the cell. I wasn't going to edit every single cell so I did some research and found out how to refresh an entire column's format.
I refreshed the column by doing the following:
Select the entire column
Format the column as necessary
Go to the Data ribbon and select 'Text-to-Columns'
Ensure Delimited is selected, click Next
Uncheck all the Delimiters, click Next, then Finish
I’m trying to dynamically update a workbook name in a formula in excel to bring through data from a continually changing source file.
So far I have been getting by with using an indirect formula, but now I have a huge workbook with around 216,000 cells to populate and I don’t think indirect is the most efficient way to do this.
I want to use VBA instead but I have no experience with this. From doing some googling I have found a few things but I’m not sure how to implement my specific needs into the code.
so far 've come up with this:
Sub replace()
Dim cell As Range
cell.Formula = replace(cell.Formula, "OfficeSupplies.csv",
"OfficeSupplies2.csv")
Range("a1:d8").Value
Next
End Sub
However, when I try to execute it, it doesn't work at all.
Edited to insert the handling of a specified range instead of ActiveSheet used range and to handle a sheet different to "Active" one
To answer the question, you could use a code like the following to replace in "Active" sheet used range:
Sub replace()
ActiveSheet.UsedRange.SpecialCells(xlCellTypeFormulas).Replace(What:="OfficeSupplies.csv", Replacement:="OfficeSupplies2.csv", LookAt:=xlPart)
End Sub
or you could explicitly refer to a sheet:
Sub replaceInSpecifiedSheet()
Worksheets("MySheetName").UsedRange.SpecialCells(xlCellTypeFormulas).Replace(What:="OfficeSupplies.csv", Replacement:="OfficeSupplies2.csv", LookAt:=xlPart) ' change "MySheetName" to your actual sheet name
End Sub
or you could want to change formulas in a given range:
Sub replaceInSpecifiedRangeOfSpecifiedSheet()
Worksheets("MySheetName").Range("A5:B8").SpecialCells(xlCellTypeFormulas).Replace(What:="OfficeSupplies.csv", Replacement:="OfficeSupplies2.csv", LookAt:=xlPart) ' change "MySheetName" to your actual sheet name
End Sub
But changing a formula in 216k cells can be quite a time consuming activity
You may consider the opposite: change the name of the”continually changing source file”
You can do that without VBA of course
Should you be “forced” to or prefer use VBA then you could use ‘Name ... As‘ statement
Sub replace2()
Dim FullNameToChange As String
Dim HardCodedFullName As String
FullNameToChange = "C:\ChangingName.xls"
HardCodedFullName = "C:\HardCodedName.xls"
If Dir(FullNameToChange) <> "" And Dir(HardCodedFullName) = "" Then Name FullNameToChange As HardCodedFullName
End Sub
Give this a try
Cells.Replace "OfficeSupplies.csv", "OfficeSupplies2.csv", xlPart, , True
Been working on this for a while, and can't seem to figure it out. I feel like I'm almost there, thanks to different posts in here. Here is what I am trying to do:
I have a dependent list that I would like to change to it's first value based on the selection of the first list. I found a code here, that I modified to work for my sheet, but I had to change all the names in the first list to conform to the Define Name rules(ie. no spaces). This works, and I can leave it at that, but I would prefer to have the spaces in my list. Whenever I use the formulas I was using to change the name shown in the list, the VBA script no longer works. I feel that it is because it is not seeing a change in the target cell, although the value is changing, the formula in the cell is not. Is that an accurate statement? If so, what can I change to make it work the way I want it to? Right now, the dependent list is running off =INDIRECT("$B$5) but I would like it to run off =INDIRECT('Store Data'!$A$23) which contains a VLOOKUP formula.
Here is the VBA script I am using now:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng(1) As Range, rng1 As Range
Set rng(0) = Range("B5") 'your primary selection
Set rng(1) = Range("G5") 'your secondary selection range
Application.EnableEvents = False
If Not Intersect(Target, rng(0)) Is Nothing Then 'if you have changed your primary selection
For Each rng1 In rng(1) 'each cell in your secondary selection
i = i + 1
rng1 = Worksheets("SD Names").Range("" & rng(0).Value2)(i, 1) 'gets changed to the nth value in the indirect reference of the primary selection ("TeamA" 's second row is "MemberA2" for example)
Next
End If
Application.EnableEvents = True
End Sub
Hope this is enough detail, thank you for any help!
The formula:
=IFERROR(IF(OR(E10=0,D9=0),0,NETWORKDAYS(D9,E9))," ")
An example of what I've tried in VBA:
Sub inputWorkdays()
Range("h9").Formula = "=IFERROR(IF(OR(E9=0,D9=0),0,NETWORKDAYS(D9,E9)),""Yes"")"
End Sub
I'm trying to add the formula from above into cell H9.
Select the cell with the formula and write the following:
Sub TestMe
debug.print Selection.Formula
debug.print Selection.FormulaR1C1
End sub
In your case it would give:
=IFERROR(IF(OR(E10=0,D9=0),0,NETWORKDAYS(D9,E9)),"YES")
=IFERROR(IF(OR(R[-4]C[-1]=0,R[-5]C[-2]=0),0,NETWORKDAYS(R[-5]C[-2],R[-5]C[-1])),"YES")
Take the first one and use it like this:
Range("h9").Formula = "=IFERROR(IF(OR(E10=0,D9=0),0,NETWORKDAYS(D9,E9)),""YES"")"
I gather from the comments that there is no error, just "nothing happens". I see nothing wrong with your code. Except...
Range("h9").Formula = "..."
When Range is unqualified like this, you implicitly refer to the ActiveSheet; if the active sheet isn't the sheet you're expecting to write to, then it's easy to conclude that "nothing happens" and that the code doesn't work.
If you have Rubberduck installed (full disclosure: I'm heavily involved with the development of this open-source VBE add-in), you will see that Range in this case is a member of Excel._Global, and an inspection result will tell you that you're implicitly referring to the ActiveSheet:
Range("H9").Formula = "..."
Implicit references to the active sheet make the code frail and harder to debug. Consider making these references explicit when they're intended, and prefer working off object references.
http://rubberduckvba.com/Inspections/Details/ImplicitActiveSheetReferenceInspection
To fix this, qualify the Range call with a Worksheet object - now the Range call is a member of the Excel.Worksheet class:
Dim sheet As Worksheet
Set sheet = ThisWorkbook.Worksheets("Sheet1")
sheet.Range("H9") = "..."
By qualifying Range calls with a worksheet object, you make sure that you're always writing to the worksheet you mean to write to - not the worksheet that happens to be the active one when the code runs.
Could you please help me in solving the following issue:
Sub PBLSearch()
Dim PBLRng As Range
Dim PBL As Range
Dim SearchRng As Range
Dim SourceWsNr As Integer
For SourceWsNr = 1 To 2
Debug.Print Workbooks("Book1.xlsx").Sheets(SourceWsNr).Name
Set PBLRng = Workbooks("Book1.xlsx").Sheets(SourceWsNr).Range(Range("A1"), Range("A1").End(xlDown))
For Each PBL In PBLRng.Cells
Debug.Print PBL.Value
Next PBL
Next SourceWsNr
End Sub
The code works fine when the SourceWsNr equals 1, but as soon as this changes to 2, i get the error mentioned in the subject.
Is it because i re-set the PBLRng variable? I couldn't find any solution to this problem...
Thank you very much in advance.
Best Regards,
S. Sz.
The problem is the line
Workbooks("Book1.xlsx").Sheets(SourceWsNr).Range(Range("A1"), Range("A1").End(xlDown))
The Range("A1") and Range("A1").End(xlDown) are referencing the cells on the active worksheet which is why it fails on the second sheet (the arguments for the range method of a sheet have to be on the same sheet). You have to specify the sheet each time when calling Range This should do it:
With ActiveWorkbook.Sheets(SourceWsNr)
Set PBLRng = .Range("A1", .Range("A1").End(xlDown))
End With
Edit: you might also consider using another way to find the last row, like .Cells(.Rows.count,1).End(xlUp). It depends on your specific needs though.