IE Automation with an array - arrays

Hello I work as a parts analyst for my company. I search engine serial numbers on our online catalog to see if the required information is present on the website for customers. I have about three thousand numbers to check each month. I have an excel sheet that I copy the engine serial number from and paste it into the search of the online catalog. Its a very tedious task. I have been working on a macro to automate this process. I have an array in the macro. I want the array to skip serial numbers that don't need to be search. So far the macro will open the browser to the e-catalog and loop through the array highlighting all the serial numbers that contain the values in the array. I now need the array to skip those values. i would like to use an if statement with the array so that each time I run the macro it will run faster because the volume of values being searched is decreasing.
Scenario
I click a button in excel it opens the required file and begins to search the serial numbers in column A.
If F2 = Y then skip searching for A2 in the catalog, however if F2 = N then search A2
If the search for A2 returns the required information then enter Y in F2, else enter N in F2, go to A3 and repeat process.
I have searched many forums and i have not been able to find a solution. The macro I have is below. I need help to complete the macro. I tried to get the array to skip the values in the array and highlight all the others by adding Not to the if statement. That did not work, instead all serial numbers were highlighted when I added "Not" to the if statement. Any suggestions are appreciated.
Sub HighlightValue()
Dim MyVals As Variant
MyVals = Array("*472908*", "*471905*", "*471914*", "*471935*", "*471917*", "*471920*", "*471933*", "*471932*", "*471934*") 'Enter all the values to search for
Application.Goto Range("A2"), False
Do Until IsEmpty(ActiveCell)
For Each esn In Selection
For i = LBound(MyVals) To UBound(MyVals)
If esn.Value Like MyVals(i) Then
esn.Interior.ColorIndex = 6 'yellow
Exit For
End If
Next i
Next esn
ActiveCell.Offset(1, 0).Select
Loop
End Sub

No problem. Here's a quick test I whipped up.
There's 2 approaches I would choose from.
Set them all to yellow and clear the colour if the entry is found in
the array
Use a flag in the loop. Set it to false before-hand, then set it to true if the entry is found in the array. After the for-loop, use the state of this flag to decide whether or not to colour the cell.
I've used approach #2.
Also note that based on the data you've presented, the wildcard (*) at the start of each string in the array is unnecessary. (I also added the last element in the array, so I'd have some cells that matched and some that didn't)
Sub highlightCellsNotInArray(myVals)
Dim found As Boolean
Application.Goto Range("a2"), False
Do Until IsEmpty(ActiveCell)
For Each engSerNum In Selection
found = False
For i = LBound(myVals) To UBound(myVals)
If engSerNum.Value Like myVals(i) Then
found = True
Exit For
End If
Next i
If found = False Then
engSerNum.Interior.ColorIndex = 6 ' yellow
End If
Next engSerNum
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Sub test()
Dim arrayVals
arrayVals = Array("472908*", "471905*", "471914*", "471935*", "471917*", "471920*", "471933*", "471932*", "471934*", "471907*")
highlightCellsNotInArray (arrayVals)
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

Convert row or column in MS Word stored table into searchable array of text in MS Word document

SUMMARY:
I would like to extract strings of text from a row or a column of cells in an MS Word table, and then use each item in the array of text strings as a search term in an MS Word VBA macro.
DETAILS:
I have been given the task of creating a macro that will search and highlight certain forbidden words in legal documents (like "hereinafter," "thus, "expressly," etc.). Then a lawyer can quickly go through the document (either visually or by searching for highlighting) and deal with the forbidden words.
I have created a macro that invokes three subroutines that will search and highlight three list of words. Right now, I must type each search term individually into the subroutine as an array:
Sub Lawyerly_Terms_1()
'
' Lawyerly_Terms_1 Macro
' Highlilghts lawyerly terms for correction
' Single words, all forms
'
Dim range As range
Dim i As Long
Dim TargetList
'HERE IS WHERE I HAVE TO TYPE EACH INDIVIDUAL SEARCH TERM. I WOULD LIKE TO IMPORT THE TERMS HIGHLIGHTED IN GREEN FROM SEARCHTERMS.DOCM.
TargetList = Array("hereinafter", "thus", "expressly", "attach", "commence", "commencement", "covenant", "desire", "desirous", "endeavor", "express", "expressly", "following", "foregoing", "subsequent", "verbatim") ' put list of terms to find here. THESE CORRESPOND TO THE YELLOW HIGHLIGHTING IN
For i = 0 To UBound(TargetList)
Set range = ActiveDocument.range
With range.Find
.Text = TargetList(i)
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = True
Do While .Execute(Forward:=True) = True
range.HighlightColorIndex = wdYellow
Loop
End With
Next
End Sub
I have three such subroutines. (Beyond the fact that I have three subroutines, this may or may not be relevant to a persons understanding of my question. I include it in case it is relevant.)
*Subroutine Lawyerly_Terms_1: The first subroutine deals with single words, with the "Find all word forms" and "Find whole words only" options selected;
Subroutine Lawyerly_Terms_2: The second subroutine deals with multi-word phrases with non-alphabetic characters, so the "Find all word forms" and "Find whole words only" options are not available; and
Subroutine Lawyerly_Terms_3: The third subroutine deals with searches that can best be done with wildcards, like "[Tt]here[a-z]{2,15}," which will find "Thereafter," "theretofore," and "thereby," but not "there" or "there's."*
However, I also have an MS Word document that has the search terms in the form of a table, called "C:\temp\SearchTerms.docm." It looks like this:
MS Word document with table containing rows and columns of search terms.
A copy is located here:
https://www.dropbox.com/s/732h3je8qweashl/MS%20Word%20Table%20for%20Search%20Macros.docx?dl=0
I think what I need to do is declare the MS Word table (or just a row or column) to be a one-dimensional array, and then to put each array into my TargetList variable, and find an iterative process for searching for each item in the array. I have tried various things I have found on helpful websites (including this one), but without success.
I was for a time rather good at coding, even briefly being a double major in computer science and theater. But that was in 1975.

VBA: Macro to copy cells that fall under condition to new tab

The code below will scan each column and copy the whole row that falls under the conditions (SEA, CUA, etc... and are red) to a sheet called "FileShares." (It is half way complete!!)
I would like two things done now, instead of copying the whole rows, I would like it to copy from source sheet (see example dataset1) the Target System (Application), UserID and Role Name to the destination sheet, "Fileshares" (see example dataset2) for each cells that matches the conditions. Only the bold headers will need to be filled. For the "Action" column, Remove needs to be placed into each row that has data.
Also, I would like to search columns dynamically up to the nth column (last column in the sheet) instead of hardcoding variable "k".
Any help, insight or suggestions would be greatly appreciated. Thanks!
Sub BulkUpload()
Dim rngCell As Range
Dim lngLstRow As Long
Dim keywords() As String, maxKeywords() As String
Dim totalKeywords As Integer, i&
Dim ws As Worksheet, resultsWS As Worksheet
Sheets.Add
ActiveSheet.Name = "FileShares"
Call Template
Set ws = Sheets("Sheet1")
Set resultsWS = Sheets("FileShares")
totalKeywords = 8
ReDim keywords(1 To totalKeywords)
ReDim maxKeywords(1 To totalKeywords)
maxKeywords(1) = "SEA"
maxKeywords(2) = "CUA"
maxKeywords(3) = "CCA"
maxKeywords(4) = "CAA"
maxKeywords(5) = "AdA"
maxKeywords(6) = "X"
maxKeywords(7) = "CUA" & Chr(10) & "SEA"
maxKeywords(8) = "CCA" & Chr(10) & "CUA" & Chr(10) & "SEA"
lngLstRow = ws.UsedRange.Rows.Count
Worksheets("FileShares").Select
j = 6
p = 1
q = 6
Dim k& ' create a Long to use as Column numbers for the loop
For k = 9 To 50
With ws
For Each rngCell In .Range(.Cells(8, k), .Cells(lngLstRow, k))
For i = LBound(maxKeywords) To UBound(maxKeywords)
If rngCell.Value = maxKeywords(i) And rngCell.Interior.ColorIndex = 3 Then
resultsWS.Cells(1000, k).End(xlUp).Offset(j + p, 0).EntireRow.Value = rngCell.EntireRow.Value
j = q + p - 7 'Used to start at row 8 and every row after
End If
Next i
Next rngCell
End With
Next k
End Sub
Excel can help you write your macros!
Using the macro recorder, perform the action manually. The recorder will transform your clicks and button presses into VBA.
Once recorded, step through your code. VBA's IDE includes a great feature. Pressing F8 allows you to advance the code one line at a time. This will help you figure out what each part of the recorded macro does. Top tip: Split your screen, so you can see both Excel and the VBA window. This will help get to grips with the code, as you see the impact each line has on the UI.
When you find a line of code you do not understand refer to Microsoft's documentation. Most items include a working example, as well as an explanation.
You can learn so much following this technique. But there is a limit. If you cannot perform the action manually, you cannot record it. To take your skills to the next level I would recommend (in order):
Attend a training course.
Read a book.
Read blogs.
Although the internet contains a wealth of information most of it is in bite sized chunks. Courses and books cover the fundamentals in detail, giving you the tools you'll need to solve these problems.
I like books published by Wrox. But I would recommend you preview a page or two before buying. I hate reading books written in a style I do not get on with.

MS Excel: "MATCH()" does not find cells containing text if lookup array is too large

I am creating a large and complicated schedule, and I want one view which shows the schedule as a day-time grid, and another which allows one to look up a speaker by name from an alphabetical list. I have posted a simplified example here:
In the alphabetical list, the day and time should be populated by a function using MATCH. Just as an example, I manually typed what I would like to have happen for Jones.
I cannot get MATCH() to locate the speaker's name in the timetable correctly. There are no hidden characters: notice that in cell D15, Excel correctly recognizes that G2 and C7 are identical.
Here is what happens if I put various code in H2:
=MATCH(G2,$A$1:$D$9) results in #N/A
=MATCH(G2,$C$2:$C$9) results in #N/A
=MATCH(G2,$B$7:$D$7) results in 2 (correctly!)
=MATCH(G2,$A$7:$D$7) results in #N/A
What I would like is to put =MATCH(G2,$A$1:$D$9) into H2 and then fill cells down to H25, and have Excel indicate the column number of the day in which the adjacent name appears, then use INDIRECT or something to convert this number into the day of the week.
It may be that including column A in the search array causes problems because of the different data types. As an experiment, I made the first column into TEXT, and in this case =MATCH(G2,$A$7:$D$7) incorrectly returns 1!
And even so, I cannot understand why $B$7:$D$7 works but neither $C$2:$C$9 nor $B$7:$D$8 will.
Any workarounds or alternative strategies would be greatly appreciated, thanks.
To do this you need to add in some other logic to find the correct column and row. This AGGREGATE() Function does the job.
For Day use:
=INDEX($A$1:$D$1,AGGREGATE(15,6,COLUMN($A$2:$D$9)/(($A$2:$D$9=G2)),1))
For Hour:
=INDEX($A$1:$A$9,AGGREGATE(15,6,ROW($B$1:$D$9)/(($B$1:$D$9=G2)),1))
The AGGREGATE() Function was introduced in Excel 2010.
For other Versions:
Pre 2010, they will need to be Array Formulas:
Day:
=INDEX($A$1:$D$1,MIN(IF($A$2:$D$9=G2,COLUMN($A$2:$D$9))))
Hour:
=INDEX($A$1:$A$9,MIN(IF($B$1:$D$9=G2,ROW($B$1:$D$9))))
Being an Array Formula it must be confirmed with Ctrl-Shift-Enter when exiting Edit mode. When done correctly Excel will automatically put {} around the formula to denote an array formula.
Newest Office 360 or online:
Day:
=INDEX($A$1:$D$1,MINIFS(COLUMN($A$2:$D$9),$A$2:$D$9,G2))
Hour:
=INDEX($A$1:$A$9,MINIFS(ROW($B$1:$D$9),$B$1:$D$9,G2))
As to the reason MATCH will not work in this case:
MATCH() only works with a single row or column and not a multiple column/row range. It is set up to return a number equal to the order place found and therefore must be a 1 dimensional array.
The most efficient way to do this given your dataset is to use three MATCH queries - one for each column.
For the Day, that looks like this:
=IF(ISERROR(MATCH(G2,$B$2:$B$10,0)),"",$B$1)&IF(ISERROR(MATCH(G2,$C$2:$C$10,0)),"",$C$1)&IF(ISERROR(MATCH(G2,$D$2:$D$10,0)),"",$D$1)
For the Time, that looks like this:
=INDEX($A$2:$A$10,IFERROR(MATCH(G2,$B$2:$B$10,0),0) + IFERROR(MATCH(G2,$C$2:$C$10,0),0) + IFERROR(MATCH(G2,$D$2:$D$10,0),0))
...but truth be told, on small datasets such as this one, you won't notice any performance difference on this approach vs Scott's AGGREGATE approach. On large datasets (thousands of rows) you probably will.
Note that another reason your initial approach failed is that you did not specify the 3rd argument of MATCH, and so Excel used the default value that assumes your list data is sorted alphabetically. You almost never want to omit that argument, and you almost always want to use FALSE (or Zero, which means FALSE to Excel)
Alternative solution with vba & listobjects (you need to give the two tables the names as appear in the code below)
sheet screenshot
Public Sub makeAppointmentList()
Dim aSheet As Worksheet
Set aSheet = ThisWorkbook.Worksheets("sheet1")
Dim aSchedule As ListObject
Set aSchedule = aSheet.ListObjects("schedule")
Dim anAppointmentList As ListObject
Set anAppointmentList = aSheet.ListObjects("appointmentList")
On Error Resume Next
anAppointmentList.DataBodyRange.Delete
On Error GoTo 0
Dim c As ListColumn
Dim r As ListRow
Dim newRow As ListRow
For Each c In aSchedule.ListColumns
For Each r In aSchedule.ListRows
If c.Index > 1 And Intersect(c.Range, r.Range) <> "" Then
Set newRow = anAppointmentList.ListRows.Add
Intersect(newRow.Range, anAppointmentList.ListColumns("Name").Range).Value = Intersect(c.Range, r.Range)
Intersect(newRow.Range, anAppointmentList.ListColumns("Day").Range).Value = Intersect(c.Range, aSchedule.HeaderRowRange)
Intersect(newRow.Range, anAppointmentList.ListColumns("Time").Range).Value = Intersect(aSchedule.ListColumns(1).Range, r.Range)
End If
Next r
Next c
anAppointmentList.Sort.SortFields.Clear
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Name").Range)
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Day").Range), _
CustomOrder:="Mon,Tue,Wed,Thu,Fri,Sat,Sun"
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Time").Range)
anAppointmentList.Sort.Apply
Dim s As SortField
End Sub

Resources