how to find multiple strings using range.value? - excel

i tried to use range("A1:I1").value to find multiple strings at the first row however it shows that error "mismatch". What have i done wrong here? Is there another way to do it?
Dim sht as worksheet
Set sht = ThisWorkbook.Sheets("Result")
If sht.range("A1:I1").value = " Voltage" and sht.range("A1:I1").value = " Time" ,<---------error 'mismatch' occurs here
call powerandtime

The problem here is that you are comparing an array of values against a single value. In case of such a small array you can make use of some Application.Methods. Another option would be to use Range.Find on the actual Range object. I'll demonstrate both below:
Application.Methods
Sub Test()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Result")
Dim arr As Variant
With Application
arr = .Transpose(ws.Range("A1:I1").Value)
If .Count(.Match(Array("Voltage", "Time"), arr, 0)) = 2 Then
Call PowerAndTime
End If
End With
End Sub
What happens here is that .Match will return an array of two elements. It will either return an error value to the array if either "voltage" or "time" is not found, or it would return a numeric value when either one of them is found. Then .Count will count numeric values within that returned array, and only if the count would be 2, is when both values are present within your initial range.
Note: .Match needs a 1D-array, hence the .Transpose at the start.
Range.Find
Sub Test()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Result")
Dim rng1 As Range, rng2 As Range
Set rng1 = ws.Range("A1:I1").Find("Voltage", lookat:=xlWhole)
Set rng2 = ws.Range("A1:I1").Find("Time", lookat:=xlWhole)
If Not rng1 Is Nothing And Not rng2 Is Nothing Then
Call PowerAndTime
End If
End Sub
So only when both "Voltage" and "Time" are found as xlWhole values within your specific range, it would continue to call PowerAndTime.

Sub testMatchBis()
Dim sh As Worksheet, rng As Range, voltPos As Long, timePos As Long
Dim rngBis As Range, arrBis as Variant
Set sh = ActiveSheet ' use please your sheet here
Set rng = sh.Range("A1:I1")
voltPos = IsMatch(rng, "Voltage")
timePos = IsMatch(rng, "Time")
If voltPos <> 0 And timePos <> 0 Then
Set rngBis = sh.Columns(voltPos)
Set rngBis = Union(rngBis, sh.Columns(timePos))
arrBis = rngBis.Value 'the both columns content will be input in an array
rngBis.Select 'both columns will be selected. Of course, you need to determine
'only part of the comumn keeping values (their last row) and limit the range
'Call call powerandtime 'You must know what this sub must do...
Else
MsgBox "(At least) one of your searched strings could not be found in the range..."
End If
End Sub
Private Function IsMatch(rng As Range, strS As String) As Long
On Error Resume Next
IsMatch = WorksheetFunction.Match(strS, rng, 0)
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
IsMatch = 0
End If
On Error GoTo 0
End Function

You could try:
Sub test()
Dim arrStrings As Variant
Dim i As Long, Counter As Long
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1:I1")
Counter = 0
arrStrings = Split("Time,Electric", ",")
For i = LBound(arrStrings) To UBound(arrStrings)
If Not rng.Find(arrStrings(i), lookat:=xlWhole) Is Nothing Then
Counter = Counter + 1
GoTo NextIteration
End If
NextIteration:
Next i
If Counter = UBound(arrStrings) + 1 Then
Call PowerAndTime
End If
End Sub

Related

VBA code to delete row in an Excel table (ListObject) if a specific cell (DataBodyRange) includes a specific substring

Summary. I am trying to loop through a table and delete each row if a particular substring is found in a specified column. I am specifically stuck on the line of code that finds the target text, which I know to be incorrect, but cannot find the proper syntax for what I'm trying to achieve: If tbl.DataBodyRange(rw, 10).Find(myString)
I have searched many websites and YouTube videos, and there are a few that address finding an exact value, but nothing I could find like the problem I'm trying to solve.
My code:
Sub removeTax()
Dim tbl As ListObject
Set tbl = ThisWorkbook.Sheets("Master").ListObjects("tblMaster")
Dim myString As String
myString = "Tax"
Dim rw
For rw = tbl.DataBodyRange.Rows.Count To 1 Step -1
If tbl.DataBodyRange(rw, 10).Find(myString) Then
tbl.ListRows.Delete
End If
Next
End Sub
Thank you very much for any assistance you can offer.
Delete Criteria Rows of an Excel Table (ListObject)
As an alternative, this uses a method that uses AutoFilter and SpecialCells.
Usage
Sub RemoveTax()
Const CritColumn As Long = 10
Const CritString As String = "*Tax*" ' contains
Dim tbl As ListObject
Set tbl = ThisWorkbook.Worksheets("Master").ListObjects("tblMaster")
DeleteTableCriteriaRows tbl, CritColumn, CritString
End Sub
The Method
Sub DeleteTableCriteriaRows( _
ByVal Table As ListObject, _
ByVal CriteriaColumn As String, _
ByVal CriteriaString As String)
With Table
If .ShowAutoFilter Then
If .AutoFilter.FilterMode Then .AutoFilter.ShowAllData
Else
.ShowAutoFilter = True
End If
.Range.AutoFilter CriteriaColumn, CriteriaString
Dim rg As Range
On Error Resume Next
Set rg = .DataBodyRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
.AutoFilter.ShowAllData
If Not rg Is Nothing Then rg.Delete xlShiftUp
End With
End Sub
I've corrected your approach, it checks if myString is sub-string of values in column 10
With tbl.DataBodyRange.Columns(10)
For rw = .Rows.Count To 1 Step -1
If InStr(1, .Cells(rw).Value2, myString) > 0 Then
tbl.ListRows(rw).Delete
End If
Next rw
End With
Keep in mind, you should check if tbl.DataBodyRange is not Nothing, before doing anything with it, since deleting all rows of a table makes DataBodyRange be equal to Nothing
I've decided to make a bit more efficient solution, more to my liking
Sub RemoveTaxQuicker()
Const myString = "Tax"
Dim tbl As ListObject
Set tbl = ThisWorkbook.Sheets("Master").ListObjects("tblMaster")
If tbl.DataBodyRange Is Nothing Then: Exit Sub
Dim rowsRangeString As String
Dim i As Long
Dim C10 As Variant
C10 = tbl.DataBodyRange.Columns(10).Value2
Dim rng As Range
If IsArray(C10) Then
Set rng = Nothing
For i = LBound(C10) To UBound(C10)
If InStr(1, C10(i, 1), myString) > 0 Then
If rng Is Nothing Then
Set rng = tbl.DataBodyRange.Cells(i, 1)
Else
Set rng = Union(rng, tbl.DataBodyRange.Cells(i, 1))
End If
End If
Next i
If Not rng Is Nothing Then
rng.Delete xlUp
End If
ElseIf InStr(1, C10, myString) > 0 Then
tbl.ListRows(1).Delete
End If
End Sub
This is no longer true :) You should use #VBasic2008 approach, I've tested it on 500k rows and it takes around 10 sec or so. And I had to test mine as well (was painfully long), it took ~5 mins. :)
Okay VBasic2008's solution forced me to think about this in a different way. The following solution executes almost instantly.
'works with formulas as well with some exceptions, thanks VBasic for pointing that as a potential problem
Sub RemoveTaxQuicker2()
Const myString = "Tax"
Const COLUMN = 10
Dim tbl As ListObject
Set tbl = ThisWorkbook.Sheets("Master").ListObjects("tblMaster")
If tbl.DataBodyRange Is Nothing Then: Exit Sub
Dim i As Long, j As Long
Dim count As Long
Dim sDataBody As Variant
Dim sFormulas As Variant
sDataBody = tbl.DataBodyRange.Formula
sFormulas = tbl.ListRows(1).Range.Formula
If tbl.DataBodyRange.Rows.count > 1 Then
For i = LBound(sDataBody, 1) To UBound(sDataBody, 1)
If InStr(1, sDataBody(i, COLUMN), myString) < 1 Then
count = count + 1
For j = LBound(sDataBody, 2) To UBound(sDataBody, 2)
sDataBody(count, j) = sDataBody(i, j)
Next j
End If
Next i
If count > 0 Then
For i = LBound(sFormulas, 2) To UBound(sFormulas, 2)
If Left$(sFormulas(1, i), 1) = "=" Then
sDataBody(1, i) = sFormulas(1, i)
End If
Next i
tbl.DataBodyRange.Formula = sDataBody
If tbl.ListRows.count > count Then
tbl.ListRows(count + 1).Range.Resize(tbl.ListRows.count).ClearContents
tbl.Resize tbl.Range.Resize(count + 1)
End If
End If
ElseIf InStr(1, sDataBody(1, COLUMN), myString) > 0 Then
On Error Resume Next
tbl.DataBodyRange.SpecialCells(xlCellTypeConstants).ClearContents
On Error GoTo 0
End If
End Sub
Final note: I still prefer VBasic's method, if nothing else it's much cleaner and it works when the table is full of formulas that are not auto-filled :)

Is it possible to get the name of a range that the active cell is in?

Scenario: Range is named "Dog" and the named range Dog refers to A1:D4. The active cell is in cell B3, which is within the named range.
Is it possible to get the name of the named range that the active cell is in? ie return the name "Dog"?
Perhaps something like the following, which tests the Intersection of the ActiveCell and each named range.
The On Error Resume Next...On Error GoTo 0 is necessary since Intersect will fail when the ActiveCell and the named range are on different sheets, or if n is not a named range but if it refers to a constant or formula, for example.
Sub test()
Dim n As Name
For Each n In ActiveWorkbook.Names
Dim rng As Range
Set rng = Nothing
On Error Resume Next
Set rng = Intersect(ActiveCell, n.RefersToRange)
On Error GoTo 0
If Not rng Is Nothing Then
Debug.Print n.Name
End If
Next
End Sub
This should be a more robust way...
Sub Test()
MsgBox NamesUsedBy(ActiveCell)
End Sub
Function NamesUsedBy(r As Range)
Dim s$, n
On Error Resume Next
For Each n In ThisWorkbook.Names
If Intersect(r, Evaluate(Mid(n, 2))).Row Then
If Err = 0 Then s = s & ", " & n.Name
End If
Err.Clear
Next
NamesUsedBy = Mid(s, 3)
End Function
There is probably a more elegant way of doing this, but this should work.
Sub test()
Dim currentrange As Range
Dim r As Variant
Set currentrange = ActiveCell
For Each r In ThisWorkbook.Names
If Not Application.Intersect(currentrange, Range(Right(r, InStr(1, r, "$")))) Is Nothing Then
Debug.Print r.Name
End If
Next r
End Sub

What is the Fastest Way to Find the First Formula in an Excel Range with VBA?

Is there any quicker method than using a for loop to find the first instance of a formula in a cell?
For Each dc In .Worksheets("testWS").Range(searchRange)
If dc.hasFormula() = True Then
formulaRow = Split(dc.Address, "$")(2)
formula = dc.formula
Exit For
End If
Next
No loop needed - use Range.SpecialCells. Include error handling since there may be no cells with formulas.
On Error Resume Next
Dim formulaRng As Range
Set formulaRng = .Worksheets("testWS").Range(searchRange).SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not formulaRng Is Nothing Then
Debug.Print formulaRng.Cells(1).Row
Debug.Print formulaRng.Cells(1).Formula
End If
Function FindFirstFormulaRow(ByRef rng As Range) As Long
Dim arrFormulas As Variant
Set arrFormulas = rng.SpecialCells(xlCellTypeFormulas)
Set rng = arrFormulas
If Not rng Is Nothing Then
FindFirstFormulaRow = Split(rng.Cells(1).Address, "$")(2)
Set rng = rng.Cells(1)
End If
End Function`

Referencing a cells address and storing it in a Range object

I am iterating through a column and wanting to catch the cells that meet the string of text that I am searching for. My problem occurs when I try and set the address of the cell that has met the criteria of the search into a Range object. Line:
Set testRng = i.Range.Adress
Gives me error " Wrong number of arguments or invalid property assignment" and I'm not sure what the issue is here?
This is the entire code I am working with:
Sub Tester()
Dim rng As Range
Dim testRng As Range
Dim i As Variant
Dim cmpr As String
Dim usrInputA As String
usrInputA = InputBox("Col 1 Criteria: ")
Set rng = Range("A2:A10")
For Each i In rng
cmpr = i.Value
If InStr(cmpr, usrInputA) Then
If testRng Is Nothing Then
Set testRng = i.Range.Address
Else
Set testRng = testRng & "," & i.Range.Address
End If
Else
MsgBox "No hit"
End If
Next
End Sub
You should declare i as a Range (not Variant)
Use Union to group together a collection of cells instead of trying to manually build the string yourself
Switch the order of your range set. You only need Set rngTest = i once so I would put this at the bottom so you don't have to keep spamming it.
Option Explicit
Sub Tester()
Dim testRng As Range, i As Range
Dim usrInputA As String
Dim LR as Long
usrInputA = InputBox("Col 1 Criteria: ")
LR = Range("A" & Rows.Count).End(xlUp).Row
For Each i In Range("A2:A" & LR)
If InStr(i, usrInputA) Then
If Not testRng Is Nothing Then
Set testRng = Union(testRng, i)
Else
Set testRng = i
End If
End If
Next i
If Not testRng is Nothing Then
'Do what with testRng?
End If
End Sub

VBA - determine if a cell value (String) matches a Value (String) in a named range

apologies if this has already been answered although I have searched and search with no luck. in a nutshell im trying to change the cell colour if that cell value does not match a value in a named range.
I have tried a number of methods although none are working for me , any help from the vba gurus would be greatly appreciated.
essentially I have a list of values on sheet1(Create) G2:G5000 that I need to know when they don't match value on sheet2(lists) S2:S64 <--this has a named range of Make.
please see a copy of my current code below
Sub testMake()
Dim MkData As Range, MkVal As Range
Dim MKArray As Variant
Set MkData = Worksheets("Create").Range("G2:G5000")
Set MkVal = Worksheets("Lists").Range("Make")
For Each MyCell In MkData
If MyCell.Value <> Range("MkVal") Then
MyCell.Interior.ColorIndex = 6
Else
MyCell.Interior.ColorIndex = xlNone
End If
Next
End Sub
Thanks you all for any help in advance, I have been looking at this for a few days now and seem to be no closer than when I started.
While I would use conditional formatting you could slightly adapt your code as below to do this programatically:
Sub testMake()
Dim MkData As Range
Dim MkVal As Range
Dim MKArray As Variant
Dim lngRow As Long
Dim rng1 As Range
Dim rng2 As Range
MKArray = Worksheets("Create").Range("G2:G5000").Value2
Set rng1 = Worksheets("Create").Range("G2")
Set MkVal = Range("Make")
For lngRow = 1 To UBound(MKArray)
If IsError(Application.Match(MKArray(lngRow, 1), MkVal, 0)) Then
If Not rng2 Is Nothing Then
Set rng2 = Union(rng2, rng1.Offset(lngRow - 1, 0))
Else
Set rng2 = rng1.Offset(lngRow - 1, 0)
End If
End If
Next
If Not rng2 Is Nothing Then rng2.Interior.ColorIndex = 6
End Sub
You could be using Worksheet function Vlookup to compare between the two ranges:
Sub testMake()
Dim MkData As Range, MkVal As Range
Dim MKArray As Variant
Dim result As Variant
Set MkData = Worksheets("Create").Range("G2:G5000")
Set MkVal = Worksheets("Lists").Range("Make")
For Each MyCell In MkData
On Error Resume Next
result = Application.WorksheetFunction.VLookup(MyCell, MkVal, 1, False)
If Err <> 0 Then
result = CVErr(xlErrNA)
End If
If Not IsError(result) Then
MyCell.Interior.ColorIndex = xlNone
Else
MyCell.Interior.ColorIndex = 6
End If
Next
End Sub

Resources