How to apply multiple criteria to .Find? - excel

I adapted code I found online.
It finds the string "car" in column A and returns the rows as an array
It assigns a variable to the length of the array (how many matches it found)
It assigns a variable to generate a random number between 0 and the length of the array
It then prints a random matching row's value into K3
Dim myArray() As Variant
Dim x As Long, y As Long
Dim msg As String
With ActiveSheet.Range("A1:A" & ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row)
Set c = .find("Car", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
ReDim Preserve myArray(y)
myArray(y) = c.Row
y = y + 1
Set c = .findNext(c)
If c Is Nothing Then
GoTo DoneFinding
End If
Loop While c.Address <> firstAddress
End If
DoneFinding:
End With
For x = LBound(myArray) To UBound(myArray)
msg = msg & myArray(x) & " "
Next x
ArrayLen = UBound(myArray) - LBound(myArray)
random_index = WorksheetFunction.RandBetween(0, ArrayLen)
MsgBox myArray(random_index)
Dim test As String
test = "B" & myArray(random_index)
Range("K3").Value = Range(test)
Example
I'm struggling with adapting the find code to allow for multiple criteria. So in my example, it finds "Car". What if I want to find matches that had "Car" in column A and "Red" in column D?
I tried
With ActiveSheet.Range("A1:A" & "D1:D" & ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row & ActiveSheet.Range("D" & Rows.Count).End(xlUp).Row)
Set c = .find("Car", "Red", LookIn:=xlValues)
I get type mismatch on the Set line.
In case it is confusing, it currently looks for a string e.g. "Car" but I will eventually link this to the variable which will be assigned to a data validation list. So if the user chooses "car" from a drop down list, this is what it will search for.

Maybe Advancde Filter is something that fit your needs:
Example Code
Option Explicit
Public Sub FilterData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim CriteriaRange As Range
Set CriteriaRange = ws.Range("A1", "E2")
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
DataRange.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=CriteriaRange, Unique:=False
End Sub
Public Sub ShowAll()
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0
End Sub
Edit according comment:
You can use the advanced filter and then loop through the filter results:
Option Explicit
Public CurrentRow As Long
Public Sub FilterData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim CriteriaRange As Range
Set CriteriaRange = ws.Range("A1", "E2")
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
DataRange.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=CriteriaRange, Unique:=False
End Sub
Public Sub ShowAll()
On Error Resume Next
ActiveSheet.ShowAllData
CurrentRow = 1
On Error GoTo 0
End Sub
Public Sub GetNextResult()
FilterData
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
Dim FilteredData As Range
Set FilteredData = DataRange.Resize(ColumnSize:=1).SpecialCells(xlCellTypeVisible)
If CurrentRow + 1 > FilteredData.Cells.Count Then
CurrentRow = 1
End If
CurrentRow = CurrentRow + 1
Dim i As Long
Dim Cell As Variant
For Each Cell In FilteredData
i = i + 1
If i = CurrentRow Then
Cell.EntireRow.Select
'or
'MsgBox Cell.Value & vbCrLf & Cell.Offset(0, 1) & vbCrLf & Cell.Offset(0, 2) & vbCrLf & Cell.Offset(0, 3) & vbCrLf & Cell.Offset(0, 4)
End If
Next Cell
End Sub

Related

Insert Row when 2 conditions are met

I have created below code which works like IF Col"B" any cell <> "" And Col"L" any cell = "Leop" then add row below to the active cell.
I mean I'm trying to achieve is to insert single row after certain row which contain in column B any value, and if column L in same row contains value = "Leop". Then add the row after that certain row.
But an error is appear. Compile Error: Invalid use of property on xlDown
Your help will be appreciated to fix it.
From this:
to this:
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long
Dim rng As Range
Dim rng2 As Range
Dim i As Long
Dim p As Long
Dim dat As Variant
Dim datt As Variant
Dim IRow As Long
Set ws = Thisworkbooks.Sheets("Sheet2")
With ws
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("B2:B" & LRow)
Set rng2 = .Range("L2:L" & LRow)
dat = rng
datt = rng2
IRow = Selection.Row
For i = LBound(dat, 1) To UBound(dat, 1)
For p = LBound(datt, 1) To UBound(datt, 1)
If dat(i, 1) <> "" And datt(p, 1) = "Leop" Then
Rows(IRow + 1).Select
Selection.Insert Shift: xlDown
End If
End Sub
It will be like in formula:
IF(AND(B2<>"",L2="Leop"),"InsertRowBelow to Row 2 If condition is met","")
and will drag it down to the lastRow.
Thisworkbooks.Sheets("Sheet2") should be Thisworkbook.Sheets("Sheet2") and missing = in Selection.Insert Shift:= xlDown
Inserting or deleting rows will change the last row number so start at the bottom and work upwards.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet, LRow As Long, r As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
LRow = .Range("B" & .Rows.Count).End(xlUp).Row
For r = LRow To 2 Step -1
If .Cells(r, "B") <> "" And .Cells(r, "L") = "Leop" Then
.Rows(r + 1).Insert shift:=xlDown
n = n + 1
End If
Next
End With
MsgBox n & " rows inserted", vbInformation
End Sub
Try this with autofilter, you dont have to loop through each row. So it will work faster for larger data.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long, cl As Range
Set ws = ThisWorkbook.Sheets("Sheet2")
LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("L1:L" & LRow).AutoFilter 1, "Leop"
For Each cl In ws.Range("_FilterDatabase").SpecialCells(12).Cells
If ws.Range("B" & cl.Row) <> "" Then
cl.Offset(1).EntireRow.Insert Shift:=xlDown
End If
Next
ws.AutoFilterMode = False
End Sub

Fetch values in Target sheet from Source sheet based on the unique ID

There are two sheets - Source and Target. There is a unique ID in both sheets in Column-A.
In TargetSheet based on the uniqueID (Column-A), I want to fetch values from SourceSheet(Column-B) to TargetSheet(Column-B).
There are unique IDs in TargetSheet(Column-A) which are not in SourceSheet(Column-A), hence they should be left blank.
Sub Recon()
Dim lrow, i, j As Long
lrow = Range("A1048576").End(xlUp).Row
TargetSheet.Activate
Range("A1").Select
j = 1
For i = 3 To lrow
Do
j = j + 1
If Range("A" & i) = SourceSheet.Range("A" & j) Then
Cells(i, 2) = SourceSheet.Range("B" & j).Value
End If
Loop Until Range("A" & i) = SourceSheet.Range("A" & j)
Next i
End Sub
You can do it combining VLOOKUP trapped into an IFERROR to handle missing ids. VLOOKUP will look a value in a column and if found, will return a value in same row but different custom column. If there is no coincidence, it will raise an error, so we combine it with IFERROR to transform that error into blank value, which means that id is not found.
VLOOKUP function
IFERROR function
My fake data is just 2 sheets like yours:
The code I've used:
Sub test()
Dim WKsource As Worksheet
Dim WKTarget As Worksheet
Dim UF As Long
Set WKsource = ThisWorkbook.Worksheets("SourceSheet")
Set WKTarget = ThisWorkbook.Worksheets("TargetSheet")
With WKTarget
UF = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("B2:B" & UF).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1]," & WKsource.Name & "!C1:C2,2,FALSE),"""")" 'get values
.Range("B2:B" & UF) = .Range("B2:B" & UF).Value 'paste formula results as values
End With
Set WKTarget = Nothing
Set WKsource = Nothing
End Sub
My final output:
Try this:
`Sub Test()
Dim Source As Range
Set Source = ThisWorkbook.Worksheets("Source").Range("A2:A5")
Dim Target As Range
Set Target = ThisWorkbook.Worksheets("Target").Range("A2:A6")
Dim TargetCell As Range
Dim FoundCell As Range
For Each TargetCell In Target
Set FoundCell = Source.Find(TargetCell.Value, _
Source.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchDirection:=xlNext)
If Not FoundCell Is Nothing Then
TargetCell.Offset(, 1) = FoundCell.Offset(, 1)
End If
Next TargetCell
End Sub`

Selecting a Excel sheet based on number

I'm new to macros and VBA in Excel. Is there a way to check if the Testvalue is between Value 1 and Value 2, and move to the corresponding sheet? And if it's not, move to the next row and repeat.
E.g.
With the testvalue 3742 sheet A21 should be selected.
Simply iterate over each row until required condition is met:
Dim testVal As Long, r As Integer
Dim yourSheet As Worksheet
Set yourSheet = Sheet1
With yourSheet
testVal = .Range("E2").Value
r = 2
Do Until (.Range("A" & r).Value <= testVal) And _
(.Range("B" & r).Value >= testVal)
ThisWorkbook.Worksheets(.Range("C" & r).Value).Activate
r = r + 1
Loop
End With
In my opinion, instead of looping each row is faster if you use Find method.
Sub test()
Dim rngSearchA As Range, rngSearchB As Range, rngFoundA As Range, rngFoundB As Range
Dim strValue As String, strSheetName As String
Dim LastRowA As Long, LastRowB As Long
With ThisWorkbook.Worksheets("Sheet1")
strValue = .Range("E2").Value
strSheetName = ""
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
LastRowB = .Cells(.Rows.Count, "B").End(xlUp).Row
Set rngSearchA = .Range("A2:A" & LastRowA)
Set rngSearchB = .Range("B2:B" & LastRowB)
Set rngFoundA = rngSearchA.Find(strValue, LookIn:=xlValues, Lookat:=xlWhole)
Set rngFoundB = rngSearchB.Find(strValue, LookIn:=xlValues, Lookat:=xlWhole)
If Not rngFoundA Is Nothing And Not rngFoundB Is Nothing Then
If .Range("C" & rngFoundA.Row).Value <> .Range("C" & rngFoundB.Row).Value Then
MsgBox "Searching value appears in both columns with different Sheet name."
Else
strSheetName = .Range("C" & rngFoundA.Row).Value
End If
ElseIf Not rngFoundA Is Nothing Or Not rngFoundB Is Nothing Then
If Not rngFoundA Is Nothing Then
strSheetName = .Range("C" & rngFoundA.Row).Value
Else
strSheetName = .Range("C" & rngFoundB.Row).Value
End If
Else
MsgBox "Value not found!"
End If
If strSheetName <> "" Then
ThisWorkbook.Worksheets(strSheetName).Activate
End If
End With
End Sub

Copying rows from one sheet to another

The following script seems like it should work, but I'm getting an "Object defined" error on the lines marked below. I can't find what's causing this at all...
Sub MailMerge()
Sheets.Add.Name = "MailMerge"
Dim MailMerge As Worksheet
Set MailMerge = Sheets("MailMerge")
Dim Rng As Range
Dim i, index, lastrow As Long
Dim Abstracts As Worksheet
Set Abstracts = Sheets("Abstracts")
lastrow = Abstracts.Cells(Rows.Count, 1).End(xlUp).row
For i = 1 To lastrow
Set Rng = Abstracts.Range("O" & i)
If WorksheetFunction.CountA(Rng) >= 1 Then
Abstracts.Range("A" & i).Resize(0, 14).Copy _
Destination:=MailMerge.Range("A" & i).Resize(0, 14)
'this is where the error is occuring
End If
Next
End Sub
Any suggestions?
Resize is not like OFFSET. It will set the size of the range to the size dictated. So you are setting the range size to 0 rows. It should be 1:
Sub MailMerge()
Sheets.Add.Name = "MailMerge"
Dim MailMerge As Worksheet
Set MailMerge = Sheets("MailMerge")
Dim Rng As Range
Dim i, index, lastrow As Long
Dim Abstracts As Worksheet
Set Abstracts = Sheets("Abstracts")
lastrow = Abstracts.Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastrow
Set Rng = Abstracts.Range("O" & i)
If WorksheetFunction.CountA(Rng) >= 1 Then
Abstracts.Range("A" & i).Resize(1, 14).Copy _
Destination:=MailMerge.Range("A" & i).Resize(1, 14)
'this is where the error is occuring
End If
Next
End Sub

Apply exclusionary criteria for multiple criteria

I am trying to have some VBA code that will apply an advanced/autofilter to exclude three variables in particular. For instance, `In this entire data set, hide entries for which Column A has values X, Y, or Z.
This code works for inclusions as far as I can tell
Sheets(sheetName).Range("$A:$" & finalCol).AutoFilter Field:=fieldIndex, criteria1:=Array("=" & crit1, "=" & crit2, "=" & crit3), Operator:=xlFilterValues
But this does not work for exclusions:
Sheets(sheetName).Range("$A:$" & finalCol).AutoFilter Field:=fieldIndex, criteria1:=Array("<>" & crit1, "<>" & crit2, "<>" & crit3), Operator:=xlFilterValues
Data validation code
Dim Arr() As Variant
Arr = Range(Cells(10, 2).Validation.Formula1)
For R = 1 To UBound(Arr, 1)
For C = 1 To UBound(Arr, 2)
Debug.Print Arr(R, C)
Next C
Next R
Is there a way to make this array "one dimensional" like in the answer?
Let's say your worksheet looks like this
LOGIC:
What we are doing is creating the array of values that we want and then passing that array to the autofilter.
CODE:
Try this code
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim Ar() As String, itm
Dim Lrow As Long, n As Long, i As Long
Dim rng As Range
Dim Col As New Collection
Dim TempAr
Dim ExclusionList As String
Dim doNotAdd As Boolean
'~~> Exclusion List
ExclusionList = "X,Y,Z"
TempAr = Split(ExclusionList, ",")
'~~> Change this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
.AutoFilterMode = False
Lrow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("A1:A" & Lrow)
'~~> Get unique collection of items
For i = 2 To Lrow
On Error Resume Next
Col.Add .Range("A" & i).Value, CStr(.Range("A" & i).Value)
On Error GoTo 0
Next i
'~~> Create an array which doesn't have the items that we don't need
For Each itm In Col
For i = LBound(TempAr) To UBound(TempAr)
If itm = TempAr(i) Then
doNotAdd = True
Exit For
End If
Next
If doNotAdd = False Then
ReDim Preserve Ar(n)
Ar(n) = itm
n = n + 1
End If
doNotAdd = False
Next
'~~> Autofilter
rng.AutoFilter Field:=1, Criteria1:=Ar(), Operator:=xlFilterValues
End With
End Sub
OUTPUT:

Resources