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

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.

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

Why does my attempt at referring to named ranges with a variant variable to which I (for-next)-store the names of ranges fail?

Apologies for the confusing title. I have multiple named ranges and I am trying to create a macro that would allow me to copy a certain row of each one of the ranges and paste it to however many following rows in each range as the user pleases. I will create 20 different macros depending on from which row the user would like to copy the selections, but for now I'm testing it with row 3.
The issue however is that I managed to store the name of the first range in a variant variable. However I have only succeeded in selecting the row with application.goto-function, but have failed in trying to copy certain rows of it. For example when I try to use the Range.(aspect(the name of my variable))-function I receive an error method 'range' of object '_Global' failed. I have also tried to create a new array based on the range that the name stored in the variable should bring but have failed in that too.
Public Sub copy_window_3()
Sheets("options").Select
ccArr = Range("ccAr").Value
copy_window rowstart:=3, copyquant:=Application.WorksheetFunction.Index(ccArr, rowstart)
Exit Sub
End Sub
Public Sub copy_window(rowstart As Double, copyquant As Variant)
Dim aspect As Variant
Dim copycounter As Integer
Dim aspcounter As Double
Dim ccArr() As Variant
Dim aspAr() As Variant
aspAr = Range("aspAr").Value
For aspcounter = 1 To UBound(aspAr, 1)
aspect = Application.WorksheetFunction.Index(aspAr, aspcounter)
Range(aspect).Rows(rowstart).Copy
For copycounter = 1 To copyquant
Range(aspect).Rows(rowstart + copyquant).PasteSpecial xlPasteValues
Next copycounter
Next aspcounter
End Sub
In case the code looks confusing: The macro first uses ccArr and rowstart variables to figure out from which row to start and how many rows to go. I intended to loop through each range name which are stored in aspAr and then copy the desired row and then loop and paste to each row that the user wishes.
Pardon me for the silly question, but I tried looking for the answer online for hours with no luck.
Thanks in advance for the help!
Cheers.

Capture specific rows of a ListObject to an array

I need help trying to figure out something I haven't done before in Excel VBA. I'm trying to assign specific (consecutive) rows of a listobject to an array. Is this possible?
Previously I was using code to copy over the entire table into the array, which worked, but it would capture unused blank rows I didn't want included. I was able to get some FUNCTIONS up and running which capture the first and low filled row numbers of the listobject for reference, but I cannot figure out how to assign ONLY this range of rows from the listobject into the array
This, for instance, works to assign only the 1st row:
varESInvoiceBreakdown = PrimeLO.ListRows(1).Range.Value
However, this doesn't work to capture the first two rows. I get an error
varESInvoiceBreakdown = PrimeLO.ListRows("1:2").Range.Value
Even though it indicates in a segment of this article that you can reference multiple rows in this manner
https://www.thespreadsheetguru.com/blog/2014/6/20/the-vba-guide-to-listobject-excel-tables
I was hoping to reference the two integer variables I have setup for the row selection.
Sincerely,
Kris
You can't index into the ListRows collection like that. Use DataBodyRange.Rows.
varESInvoiceBreakdown = PrimeLO.DataBodyRange.Rows("1:2").Value
With variables:
Dim startRow as Long
Dim endRow as Long
startRow = 1
endRow = 2
varESInvoiceBreakdown = PrimeLO.DataBodyRange.Rows(startRow & ":" & endRow).Value

IE Automation with an array

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

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