I have the following code
Dim Shop1 As String
With Worksheets("Data Page")
Shop1 = Application.WorksheetFunction.Index(.Range("B2:B7"), Application.Worksheet.Match(profitable1, .Range("E2:E7"), 0))
End With
This is how my excel looks like
The code works at first, but after I change some value,it suddenly does not and the above error pops out.
Can someone tell me why? Thank you so much for helping
Application.Match vs WorksheetFunction.Match (WorksheetFunction.Index)
You have misspelled WorksheetFunction in your code as mentioned by
Raymond Wu in the comments: Worksheet.Match should be WorksheetFunction.Match.
The early-bound WorksheetFunction version of Match will raise an error if a value is not found so you will have to implement some kind of error handling. The late-bound Application version is preferred because it can be tested with IsNumeric or IsError.
I can't recall using Index/Match in VBA. It is usually handled as illustrated in the following code.
Option Explicit
Sub Test()
Dim sIndex As Variant ' a number or an error value, hence 'As Variant'
Dim profitable1 ' ?
Dim Shop1 As String ' this actually means Shop1 = ""
With ThisWorkbook.Worksheets("Data Page")
With .Range("E2:E7")
sIndex = Application.Match(profitable1, .Cells, 0)
If IsNumeric(sIndex) Then
Shop1 = CStr(.Cells(sIndex).EntireRow.Columns("B").Value)
' Or:
'Shop1 = CStr(.Cells(sIndex).Offset(, -3).Value)
'Else ' if the code is in a loop
' Shop1 = ""
End If
End With
End With
End Sub
It becomes simpler (more readable) when using range variables.
Sub Test2()
Dim sIndex As Variant ' a number or an error value, hence 'As Variant'
Dim profitable1 ' ?
Dim Shop1 As String ' this actually means Shop1 = ""
Dim lrg As Range ' Lookup
Dim vrg As Range ' Value
With ThisWorkbook.Worksheets("Data Page")
Set lrg = .Range("E2:E7")
Set vrg = .Range("B2:B7")
End With
sIndex = Application.Match(profitable1, lrg, 0)
If IsNumeric(sIndex) Then
Shop1 = CStr(vrg.Cells(sIndex).Value)
'Else ' if the code is in a loop
' Shop1 = ""
End If
End Sub
Related
I am trying to develop a custom function to check if the data in a listobject is filtered.
Public Function TestFiltered() As Boolean
Dim rngFilter As Range
Dim r As Long, f As Long
Set rngFilter = ActiveSheet.AutoFilter.Range
r = rngFilter.Rows.Count
f = rngFilter.SpecialCells(xlCellTypeVisible).Count
If r > f Then TestFiltered = True
End Function
However I am getting an error "Object variable not set" in Set rngFilter = ActiveSheet.AutoFilter.Range
All of my sheets will only have one listobject, but perhaps it is safer to somehow change the function to apply the range for the first listobject found in the activesheet?
The idea of multiplying the columns and the rows and comparing them with filterArea.SpecialCells(xlCellTypeVisible).Count is rather interesting. This is what I managed to build on it:
Public Function TestFiltered() As Boolean
Dim filterArea As Range
Dim rowsCount As Long, cellsCount As Long, columnsCount As Long
Set filterArea = ActiveSheet.ListObjects(1).Range
rowsCount = filterArea.rows.Count
columnsCount = filterArea.Columns.Count
cellsCount = filterArea.SpecialCells(xlCellTypeVisible).Count
If (rowsCount * columnsCount) > cellsCount Then
TestFiltered = True
End If
End Function
Here's another approach that tests a specific listobject. It first uses the ShowAutoFilter property of the ListObject to determine whether the AutoFilter is dislayed. If so, it then uses the FilterMode property of the AutoFilter object to determine whether it's in filter mode.
Option Explicit
Sub test()
Dim listObj As ListObject
Set listObj = Worksheets("Sheet2").ListObjects("Table1") 'change the sheet and table names accordingly
If IsListobjectFiltered(listObj) Then
MsgBox listObj.Name & " is filtered", vbInformation
Else
MsgBox listObj.Name & " is not filtered.", vbInformation
End If
End Sub
Function IsListobjectFiltered(ByVal listObj As ListObject) As Boolean
If listObj.ShowAutoFilter Then
If listObj.AutoFilter.FilterMode Then
IsListobjectFiltered = True
Exit Function
End If
End If
IsListobjectFiltered = False
End Function
Try along these lines
Dim i As Long
Dim isFiltered As Boolean
' test if AutoFilter has been turned on in the active sheet
If ActiveSheet.AutoFilterMode Then
' loop through the filters of the AutoFilter
With ActiveSheet.AutoFilter.Filters
For i = 1 To .Count
If .Item(i).On Then
isFiltered = True
Exit For
End If
Next i
End With
End If
This will also work if you are using Tables in Excel. I am using something like this in an If-Then statement to see if the number of rows in the first column matches the number of visible cells in the first column:
Dim tbl As ListObject
Set tbl = ActiveSheet.ListObjects("Table1")
If tbl.ListColumns(1).DataBodyRange.Rows.Count <> tbl.ListColumns(1).DataBodyRange.Rows.SpecialCells(xlCellTypeVisible).Count Then
'Do something if True
End If
I am making a vlookup code that shows the user description when they scan item barcode but I am getting subscript out of range error
Dim ws As Worksheet
Set ws = Sheets("CONVERSION")
Dim itemcode As String
Dim description As String
Dim myrange As Range
ws.Activate
Set myrange = Range("A:B")
description = ws.Application.WorksheetFunction.VLookup(TextBox1.Value, Worksheets("CONVERSION").Range("myrange"), 2, False)
Label5 = description
Then it is supposed to assign the value of the vlookup (description) to the label
This should help:
Option Explicit
Sub Test()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("CONVERSION") 'if you don't define the workbook it will be the activeworkbook
Dim itemcode As String
Dim description As Variant 'Defining it as variant won't rise an Error if the item is not found
Dim myrange As Range
Set myrange = ws.Range("A:B") 'If you define a worksheet, you can refer to it and you won't need .Select or .Activate
description = Application.VLookup(TextBox1.Value, myrange, 2, False) 'as before, once you defined your range you can simply refer to it
If Not IsError(description) Then
Label5 = description
Else 'if nothing is found description will be an error
Label5 = "Item not found"
End If
End Sub
Application.VLookUp instead using the WorksheetFunction will prevent VBA to rise an error in case nothing is found when it's applied to a Variant so you can use that little trick to later do the if I've posted you in case your BarCode isn't yet on your database.
Ok Finaly Fixed the Problem , not the way i originaly thought but it does the job , i stopped using vlookup and did this
Dim Found As Range
Dim str As String
str = Me.TextBox1.Text
Set Found = Sheet2.Range("A2", Range("A" & Rows.Count).End(xlUp)).Find(str)
If Found Is Nothing Then
Label5 = "Not Found"
Else
Label5 = Cells(Found.Row, 2).Value
End If
i found the solution here
I am looking for a way to do =MATCH(VALUE(A1), VALUE(B:B), 0) in vba in excel.
I have two columns that I am matching, both might be interger or string types. I know how I would do this but it involves many if statements. I was wondering if there is an elegant way to do this.
You can do this with a WorksheetFunction.Match method...example below (commented for explanation):
Sub test()
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Dim lookuprng As Range
Dim res
Set wb = ThisWorkbook
Set ws = wb.ActiveSheet
Set rng = ws.Range("A1")
Set lookuprng = ws.Range("B:B")
On Error Resume Next
res = Application.WorksheetFunction.Match(rng.Value, lookuprng, 0) 'will return a row number
If Err.Number > 0 Then 'the above command will throw an error if there is no match
MsgBox "No Match!", vbCritical
Err.Clear
Else
'do something with the matched row
End If
End Sub
Evaluate() have a limit, max 255 Characters only, if your formula too lengthy will have an error.
I recommend to use Application.Match(), rather Application.WorksheetFunctions.Match().
Both method are Identical, except the respond, when there have no Macthed value.
You can use IsError(Application.Match()) to check if value able to match, without the need of Error Handler. Return True if not able to match.
Using Application.WorksheetFunctions.Match() will need Error Handler.
I have hundreds of Columns in excel that I don't need. I have a range that I want to keep.
At the minute I have
Sub DeleteClms ()
Range("A:G,L:O").Delete
End Sub
Is there anyway to make this an opposite, in other languages I would simply put a =!.
I have tried putting <> in but I dont know where/how to put it into my code?
Thanks
There is no Excel or VBA function for the Symetric Difference of the columns that I know of.
Here is a quick VBA function to get there. Usage would be DeleteAllBut Range("A:C,H:Q")
Sub DeleteAllBut(rngToKeep As Range)
Dim ws As Worksheet
Dim rngToDelete As Range
Dim rngColi As Range
'Number of columns used in worksheet
Set ws = rngToKeep.Parent
iCols = ws.UsedRange.Columns.Count
FirstOne = True
For i = 1 To iCols
Set rngColi = Range("A:A").Offset(0, i - 1)
If Intersect(rngToKeep, rngColi) Is Nothing Then
If FirstOne Then
Set rngToDelete = rngColi
FirstOne = False
Else
Set rngToDelete = Union(rngColi, rngToDelete)
End If
End If
Next i
Debug.Print rngToDelete.Address & " was deleted from " & ws.Name
rngToDelete.Delete
End Sub
I am new in VBA coding. Lets say I am retrieving value from Sheet3.Cell(23, 4) for a value, is there any way in the VBA code which let me set this as a variable?
For example, I have changed the interface and let the value stay at Sheet4.Cell(20,1), everywhere in my code which refer to Sheet3.Cell(23, 4) need to be changed to Sheet4.Cell(20, 1). I am thinking is there any best practice for coding VBA for situation like this?
Yes. For that ensure that you declare the worksheet
For example
Previous Code
Sub Sample()
Dim ws As Worksheet
Set ws = Sheets("Sheet3")
Debug.Print ws.Cells(23, 4).Value
End Sub
New Code
Sub Sample()
Dim ws As Worksheet
Set ws = Sheets("Sheet4")
Debug.Print ws.Cells(23, 4).Value
End Sub
Yes, set the cell as a RANGE object one time and then use that RANGE object in your code:
Sub RangeExample()
Dim MyRNG As Range
Set MyRNG = Sheets("Sheet1").Cells(23, 4)
Debug.Print MyRNG.Value
End Sub
Alternately you can simply store the value of that cell in memory and reference the actual value, if that's all you really need. That variable can be Long or Double or Single if numeric, or String:
Sub ValueExample()
Dim MyVal As String
MyVal = Sheets("Sheet1").Cells(23, 4).Value
Debug.Print MyVal
End Sub