VBA Excel vlookup in loop problem - loops

I have a problem with my VBA code in an excel spreadsheet containing orders. Each row contains a customer number, which I use to look up the customer email address, contained in a different sheet in the workbook.
The vlookup code works fine for a single cell, but the problem is when I try to loop through all of the rows of the spreadsheet. The Excel formula for a single cell is, e.g.,
=VLOOKUP(B2,Customers!A2:D1000,4,FALSE)
The VBA code generated for this is:
Range("M2").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-11],Customers!RC[-12]:R[999]C[-9],4,FALSE)"
Incorporating this into a loop, after selecting the starting cell, I have the following:
Cells(2, 13).Select
Do
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-11],Customers!RC[-12]:R[999]C[-9],4,FALSE)"
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell.Offset(0, -10))
The problem is that I want the "table array" to be fixed, not relative to the cell whose value is being looked up. But I absolutely can't figure out how to do it. If I change the code as follows, I get a run-time error:
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-11],Customers!A2:D1000,4,FALSE)"
I have tried quoting, unquoting, setting a range variable, using the range variable with .address... can someone please help?
Thank you so much.

I'm pretty sure the brackets in your R1C1 formula indicate that you are specifying a relative range (especially with the negatives in them). If you want to specify an absolute range, you need to specify the R1C1 cells without brackets; e.g. R2C2:R4C4.
As a simple example:
Sub test()
Sheet1.Range("C5").FormulaR1C1 = "=VLOOKUP(1,R1C1:R3C3,2,FALSE)"
End Sub
Running this gives you an absolute "A1"-style formula in cell C5.
I think your problem might be:
Customers!RC[-12]:R[999]C[-9]
Because it is a relative range. You have to explicitly specify where your data table is; e.g. Customers!RC12:R999C9 (you need to figure out where it is on your sheet).
An easy way of figuring this out is highlighting your data table on your worksheet, then switch to the Visual Basic Editor and manually run this (put your cursor inside of the Sub, and press the 'Play' button or go to Run->Run).
Sub test2()
Dim r As Range
Set r = Application.Selection
InputBox "your r1c1 range:", , r.Address(True, True, xlR1C1)
End Sub

Related

How do I use an array of ranges to propagate data for a search

it's 3:20 am and I'm about spent, so I'm tossing this up here in hopes someone can help me. I'm not sure this is a difficult problem, but I don't honestly know how to ask this clearly.
I made a User Form a couple of weeks ago with some help here to let users store information into a table. I'm now making a Search form to allow them to search the table (namely the full name column) and as there will be multiple entries with the same name, have it propagate a combo box so that the user can choose which entry they want to view. Depending on which entry they choose in the combobox will also propagate all the fields below it.
First, I think I've got the search function working correctly and building the array of ranges right. I had originally stored the array as strings and it populated my combo box perfectly, but then I had lost the range/address to propagate other data later. So I switched it back to an array of ranges and from there I'm having problems. Currently if I use the Combobox.additem I will of course only get a range from my array, but I can't do something like LookUpTable.Range(Array(i)).Value for my AddItem either. So, I'd like to be able to figure out how to propagate the combobox with the values in those stored ranges. I think once I learn how to do that, propagating the other fields afterwards will be pretty straightforward.
I hope this makes sense. Apologies, my brain is fried and I need some sleep.
EDIT:
The combobox will be propagated with all the duplicates as well as an identifier to easily separate them (in this case the date and person who did the evaluation) so that the user can choose which evaluation they would like to view. Right now it just shows the Full Name which is the stored range. I want to be able to essentially use the stored range to grab the entire row of values in another array that can then propagate all the fields for that report. I could make an array for every result at the time of searching, but this would be inefficient I think. Instead it should be created once the user chooses which report they want to view so it's limited to only making one array. I think I can maybe figure that out, but because it happens after they choose from the combobox, I'm unable to figure out to use that one range and pull two more columns of data with it. If I try using ,Offset with it I get an "Expected Object" error. If I try using my Table and the Array value for a range, I get a different error. I hope all this makes sense.
Public Sub Search_button_Click()
Dim NameColumn As Range
Dim NameLookUp As Range
Dim SearchResultsArray() As Variant
Dim SearchResultsCounter As Integer
Dim ResultsPropagate As Integer
Dim FirstResult As String
'Sets/Resets counter to 1 each time search button is pressed
SearchResultsCounter = 1
'Converts the text box values to strings and uppercases the first character and combines them into a full name value.
FirstLookUp = StrConv(StudentFirst_textbox.Value, vbProperCase)
LastLookUp = StrConv(StudentLast_textbox.Value, vbProperCase)
FullLookUp = FirstLookUp & " " & LastLookUp
'Sets NameColumn to the Full Name column in the table
Set NameColumn = LookUpTable.Range.Columns(3)
'Sets NameLookUp to the Full Name column in the table and searches for the FullLookUp string
Set NameLookUp = LookUpTable.Range.Columns(3).Find(What:=FullLookUp, LookIn:=xlValues, _
LookAt:=xlPart, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
'Saves the first result to prevent infinit looping and readjusts the array to match results size.
If Not NameLookUp Is Nothing Then
FirstResult = NameLookUp.Address
ReDim Preserve SearchResultsArray(SearchResultsCounter)
SearchResultsArray(SearchResultsCounter) = NameLookUp
Do
ReDim Preserve SearchResultsArray(SearchResultsCounter)
SearchResultsArray(SearchResultsCounter) = NameLookUp
Set NameLookUp = NameColumn.FindNext(NameLookUp)
SearchResultsCounter = SearchResultsCounter + 1
Loop Until NameLookUp Is Nothing Or NameLookUp.Address = FirstResult
SearchResults_combobox.AddItem ("Choose a result to view.")
For ResultsPropagate = LBound(SearchResultsArray) To UBound(SearchResultsArray)
SearchResults_combobox.AddItem (SearchResultsArray(ResultsPropagate)) 'Here I want to use the range stored in the array and pull the value from the table.
Next ResultsPropagate
SearchResults_combobox.ListIndex = 0
Else
MsgBox "Sorry, no entries matched your search.", vbOKOnly
End If
End Sub

Excel VBA: Create Array from Filter Field Items?

A report I am creating in Excel involves several very similar pivot tables needing to be specifically filtered many times (i.e. a Year-to-Date table, a Quarter-to-Date table, etc, all needing to be filtered the exact same way before exported, then filtered again, then exported, etc)
So I looked into VBA as a way of accepting a few filter criteria, then filtering multiple tables that way, before looping.
However, I'm having a very tough time properly targeting PivotTables and specific fields, as it appears an integrated Value field is targeted and filtered via code differently than, say, a "filter' field I have attached to the top of the PivotTables, where they can accept no "begins with", "contains", etc, strings. They are just checkboxes, and one or multiple can be selected.
So it's one thing for me to tell it via VBA to select one item, and having it select all but one item. The latter requires the code to target every single possible value, but not the one that I want excluded.
My idea for this, then, is to create an array from every possible existing value in this filter field, then going through a loop where each value is added to my code as a value to check.
I have some code so far:
ActiveSheet.PivotTables("QTD_Pivot_By_Category").PivotFields( _
"[Range].[Address_1].[Address_1]").VisibleItemsList = Array( _
"[Range].[Address_1].&", "[Range].[Address_1].&[0]", "[Range].[Address_1].&[101]" _
, "[Range].[Address_1].&[INC]", "[Range].[Address_1].&[KRT]", _
"[Range].[Address_1].&[LTD]", "[Range].[Address_1].&[RPO]", _
"[Range].[Address_1].&[ INC]", "[Range].[Address_1].&[CORP]", _
"[Range].[Address_1].&[INC.]", "[Range].[Address_1].&[LTD.]", _
"[Range].[Address_1].&[LTEE]", "[Range].[Address_1].&[PAWS]", _
Now, if I just record this macro from actions in Excel, and do "select All", then de-select the one I don't want, it will error. It errors because it's selecting ~300 values, and while it's 'writing' this code, it errors when it hits the limit of "_" delimited breaks in one straight line of VBA code.
If my field is called "Address_1" as above, part of the range..."Range" (not sure where that's defined or why, but it works), can I get some help as to the most efficient way to define said ".VisibleItemList" as all POSSIBLE items in the list from a dynamic array rather than needing to be selected manually? This list will be different day-to-day so it can't just be a hardcoded flat list.
Ideally, also in a way that circumvents the max limit on "_" line breaks in a line of code in VBA for Excel.
If it's of any use for context, my table looks like this. See that checkbox drop-down? I want a snapshot of every updated value sitting in there to be put into an array and then iterated upon being added in a way similar to my example code:
Edit:
Since that filter field's values are being pulled from a local datasource, I decided to just grab those and make an array that way! So I'm starting my code this way:
Dim OGDataRange As Range, OGDataLastRow As Long
Dim ValueArray As Variant
OGDataLastRow = Worksheets("DATA QTD").Range("U2").End(xlDown).Row
Set OGDataRange = Worksheets("DATA QTD").Range("U2:U" & OGDataLastRow)
ValueArray = OGDataRange.Value
"ValueArray" is now my array. So I need help one-by-one pulling the values of this array, and adding them to my VisibleItemList as seen above.
Thank you so much for any assistance.
This might help you
Private Sub this()
Dim pf As PivotField
Dim pi As PivotItem
Dim strPVField As String
strPVField = "this"
Set pt = ActiveSheet.PivotTables("PivotTable1")
Set pf = pt.PivotFields(strPVField)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
On Error Resume Next
pf.AutoSort xlManual, pf.SourceName
For Each pi In pf.PivotItems
pi.Visible = False
Next pi
pf.AutoSort xlAscending, pf.SourceName
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
borrowed from
Deselect all items in a pivot table using vba

How to insert array formula into Excel via VBA?

Previously I have an Excel VBA code that performs index & match formula from 1 sheet to another for an entire column in a table. Code example as below:
With Me.Range("table1[Description]")
.Formula = "=IFerror(INDEX(table2,MATCH(B4,table2[Asset No],0),2),"""")"
.Value = .Value
End With
Now I would like to add an array function into the sheet so I copied the formula and replace the old formula with array along with other modifications.
Sub refresh()
With Me.Range("table1[Last Service Date]")
.FormulaArray = "=LARGE(IF(table2[[#All],[Asset No]]=[#[Asset No]],table2[[#All],[Entry Date]]),2)"
.Value = .Value
End With
End Sub
But when I try to test the code, I keep getting the error message 400.
Anything I need to change in my code for array formulas?
What's the point of using Me in the code? Have you placed that code in the Sheet Module? I would suggest you to move this code on to the Standard Module like Module1 and replace the Me keyword with the proper sheet reference. Otherwise I hope you have a good reason to place that code into the sheet module.
Also you should place the Array Formula in the first cell of the table in the desired column and since the data is formatted as an Excel Table, the whole column will be filled with the formula automatically. If not, you can then use AutoFill property to fill down the formula down the rows.
Give this a try to see if that resolves your issue.
The answer assumes that the formula you are trying to place through VBA works well when you put it manually on the Sheet.
With Me.Range("table1[Last Service Date]").Cells(1)
.FormulaArray = "=LARGE(IF(table2[[#All],[Asset No]]=[#[Asset No]],table2[[#All],[Entry Date]]),2)"
.Value = .Value
End With

Excel Sumif Array- works in sheet returns false in vba

I have a question regarding the sumif array function in excel.
My current formula works perfectly when typed to a cell and used as a array Ctrl + Shift + Enter and the filled down the column with the double click.
the formula is =SUMIFS(T:T,A:A,A2,C:C,"<"&OFFSET($H$1,MATCH(1,(A:A=A2)*(H:H=[IPE.xlsm]Overview!$C$3),0),-5))
My problem is when I try to integrate this formula into my current vba script.
Below is the section where Im running into this error.
when the code is run it returns a false statement, again though if I copy paste the formula it returns the correct value.
Sub Enter_Array_Formulas()
Range("W2").FormulaArray = "=SUMIFS(T:T,A:A,A2,C:C," < "&
OFFSET($H$1,MATCH (1,(A:A=A2)*(H:H=[IPE.xlsm]Overview!$C$3),0),-5))"
Range("U2").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 2).Select
Range(Selection, Selection.End(xlUp)).Offset(0, 0).Select
Selection.FillDown
End Sub
Im guessing its a syntax error but I'm unable to find the hiccup.
Thanks in advance,
Ross
Try this instead:
Range("W2").FormulaArray = "=SUMIFS(T:T,A:A,A2,C:C,""<""&OFFSET($H$1,MATCH(1,(A:A=A2)*(H:H=[IPE.xlsm]Overview!$C$3),0),-5))"
You need to be careful when using speech marks in strings -- use two "" instead
Also, you entered a blank space after MATCH, which would be corrected for you on the worksheet but probably just throws an error in VBA.

How to select 2-dimensional ranges using variables and not "A1"-format?

I realize this must be a really basic question but I can't seem to get this right. This last month of trying to learn VBA always sees me stuck on problems relating to this. I have searched for the answer but still struggle. Some help would be appreciated!
So, what I want to do is to select and manipulate ranges based on their numeric order, like row1,col1 to row 15,col7. Instead of "A1:G15".
For instance, the following code should format the copy of a pivot table:
Sub layout()
Dim searchterm As String: searchterm = "Grand Total"
rad = RowIndexer(searchterm) 'finds location of last row
kolumn = ColIndexer(searchterm) 'finds location of last column
ActiveSheet.Range(Cells(15, 1), Cells(rad, kolumn)).Style = "SAPBEXfilterItem"
End Sub
I have also tried converting the range to "A1"-style, to no avail:
Start = Cells(counter, 1).Address
Finish = Cells(counter, kolumn).Address
Range("Start:Stop").Style = "SAPBEXfilterItem"
This question is very generic though so don't focus too much on the actual application. Just tell me how to work with ranges when you usually have just indices :)
In both cases I'm only able to select the first column and not the entire range. I heard someone mention that VBA is not "matrix based" and a lot of code I look at seems to overuse loops. Is the problem actually that you can only manipulate one one-dimensional array at a time? That would be really annoying...
You can indeed select ranges by using Range and using Cells(row, column). The correct usage is as follows, to select A1:G15
Dim wS as Worksheet
Set wS = ActiveSheet
Range(wS.cells(1,1), wS.cells(15,7)).select
Note that I did specify which sheet I am using INSIDE the Range method and applied to the cells object. That's the proper way to do it.

Resources