VBA Match Function "Method 'Match' of Object 'WorksheetFunction' Failed" - vba

I'm trying to use the Match VBA function in a programming project in Excel to get the first row number with a "1" in it. The code I'm using is:
Dim BorradorVar As Integer
BorradorVar = WorksheetFunction.Match(1, Sheets("Usuarios").Range("A1,A100"), 0)
Can someone explain what I'm doing wrong? Thanks!

You should refer to Range as
Range("A1:A100")
instead of
Range("A1,A100")
Using comma you refer to A1 and A100 only.
Also, if you are not sure if there is a match or not, you can use Application.Match and store the result in a Variant variable instead. The difference is that Application.Match returns an error when it fails, and then you can check if it has failed or not.
Example (check MSDN for full code):
Dim var As Variant
var = Application.Match(Cells(iRow, 1).Value, Worksheets(iSheet).Columns(1), 0)
If Not IsError(var) Then
Debug.Print "There is actually a match"
Else
Debug.Print "No match found"
End IF
A word of warning: If you match after row 32,767 your code will not run, because it exceeds the range of Integer. I suggest using Long instead of Integer. Using Long is better practice in VBA anyway.
Finally, note that if someone changes the name of the worksheet, this code will not run. It is safer to refer to the worksheet by using its sheet ID instead of its name (Disclaimer: I have written the accepted response to that question).

Related

VBA: Using Array Formula

I want to find a row number based on two criteria, in column C and E. My data looks like this:
I have googled my problem and using the Match function as an array formula works for this (worked when I used it in Excel, not VBA), but I can't figure out how to make it an array formula in VBA. Different solutions, be it using "[]" or .Evaluate didn't work for me (maybe that was my mistake, though). So how would I modify this code to get the result I want:
Sub Test1()
Dim rowDB As Long
Dim wsDB As Worksheet
Set wsDB = ActiveSheet
rowDB = WorksheetFunction.Match(CDate("30.06.2020") & "EX0500-0001", wsDB.Range("C7:C366") & wsDB.Range("E7:E366"))
End Sub
The error I get is "error 13: type mismatch", so I'm not sure if there's another issue here or just the lack of an array formula.
I played with this for a bit and found several problems:
It seems that CDate() doesn't like "30.06.2020" as input and gets a type error. It seems to be happy with "30-06-2020" so maybe use that format instead or just search for string "30.06.2020" instead? This should be ok as long as all of the date formats are consistent.
The WorksheetFunction.Match() second parameter must be a contiguous range and yours is not. Also I don't think the expression wsDB.Range("C7:C366") & wsDB.Range("E7:E366") makes sense; if you want to combine ranges use the Union() function. But this will not work here because as mentioned the range is not contigous.
I don't think it is possible to use WorksheetFunction.Match() to search for multiple values, so you might have to search for the date in coulmn C and the string in column E separately.
Here is some vba I got working for just searching for one value:
Sub Test4()
Dim rowDB As Long
Dim wsDB As Worksheet
Set wsDB = ActiveSheet
rowDB = WorksheetFunction.Match("30.06.2020", wsDB.Range("C7:C366"))
Debug.Print rowDB
End Sub
Also, If a match is not found, it will get a "Application-defined or object-defined error" so you will need to implement some error handling.

Add-in function Range.Delete method fails

First, I would like to apologize for my bad language, I hope you'll understand my problem.
I looked after a way to get generic function in Excel and I found the add-in method. So I tried to use it in developping custom functions whitch may help me in my everyday work. I developed a first function which work. So I thought that my add-in programmation and installation was good. But when I try to implement worksheet interractions nothing appened.
My code has to delete rows identified by a special code in a cell of those ones. I get no error message and the code seems to be totally executed. I tried other methods like Cells.delete, Cells.select, worksheet.activate or range.delete but I encounter the same issue.
This is my function's code :
Public Function NotBin1Cleaning(rSCell As Range) As Integer
Dim sht As Worksheet
Dim aLine As New ArrayList
Dim iLine As Integer
Dim iCpt As Integer
Dim iFail As Integer
Dim i As Integer
Dim oRange As Object
Set sht = rSCell.Parent
iLine = sht.Cells.Find("*PID*").Row
For Each rCell In Range(sht.Cells(iLine, 1), sht.Cells(sht.Cells(iLine, 1).End(xlDown).Row, 1))
If sht.Cells(rCell.Row, 2) > 1 Then
iLine = rCell.Row
iCpt = iLine + 1
Do Until sht.Cells(iCpt, 2) = 1
If Not sht.Cells(iCpt, 1) = rCell Then Exit Do
iCpt = iCpt + 1
Loop
If sht.Cells(iCpt, 1) = rCell Then
sht.Range(sht.Cells(iLine, 1), sht.Cells(iCpt - 1, sht.Cells(iCpt, 1).End(xlToRight).Column)).Delete xlUp
iFail = iFail + 1
End If
End If
Next
NotBin1Cleaning = iFail
End Function
it's the line:
sht.Range(sht.Cells(iLine, 1), sht.Cells(iCpt - 1, sht.Cells(iCpt, 1).End(xlToRight).Column)).Delete xlUp
which isn't producing any effect.
I would be really thankful for your help.
This issue is described on the Microsoft support site as part of the intentional design
section below, more detail here (emphasis mine)
A user-defined function called by a formula in a worksheet cell cannot change the environment of Microsoft Excel. This means that such
a function cannot do any of the following:
Insert, delete, or format cells on the spreadsheet.
Change another cell's value.
Move, rename, delete, or add sheets to a workbook.
Change any of the environment options, such as calculation mode or screen views.
Add names to a workbook.
Set properties or execute most methods.
The purpose of user-defined functions is to allow the user to create a
custom function that is not included in the functions that ship with
Microsoft Excel. The functions included in Microsoft Excel also cannot
change the environment. Functions can perform a calculation that
returns either a value or text to the cell that they are entered in.
Any environmental changes should be made through the use of a Visual
Basic subroutine.
Essentially, this means that what you're trying to do won't work in such a concise manner. The limitation, as I understand from further reading, is because Excel runs through cell equation/functions several times to determine dependencies. This would lead to your function being called two or more times. If you could delete rows, there is the potential of accidentally deleting more then twice the numbers of rows intended, due to the excess number of runs.
However, an alternative could be to have the function output a unique string result that shouldn't be found anywhere else in your workbook (maybe something like [#]><).
Then you can have a sub, ran manually, which finds all instances of that unique string, and deletes those rows. (Note: if you included any of the typical wildcard symbols in your string, you will have to precede them with a ~ to find them with the .Find method.) You can even set up the sub/macro with a shortcut key. Caution: if you duplicate a shortcut key Excel already uses, it will run the macro instead of the default. If there will be other users using this workbook, they could experience some unexpected results.
If you decide to go this route, I would recommend using this line:
Public Const dummy_str = "[#]><" ' whatever string you decided on.
in your module with your code. It goes outside any functions or subs, so it'll be global, and then you can refer to the const just as you would any other string variable.
When you write:
sht.Range(sht.Cells(iLine, 1),....
This first parameter should be the row number, but you're refering to a Cell instead. You should change sht.Cells(iLine, 1) for iLine.
BUT
Instead of all this, its easier to use the method Row.Delete:
Rows(iLine).EntireRow.Delete

Type Mismatch error in function using DateValue(), how to troubleshoot?

Warning: I'm a noob.
I've written a Sub to find cells with red text and alter them.
#ThinkerIV gave me a great function to put in a cell and drag the formula out into adjoining cells, but that won't work due to the number of sheets to work on.
So I wrote my Sub, calling his function (see code below). I passed it a Range of one cell, so it seems to me it should work?
But, it keeps throwing out Type Mismatch (run-time error code 13) on the line where the function calls the DateValue()! The passed range shows a value of 1 (which is the number in the cell it refers to) when I hover over it in the editor, but I don'rt know if that's the cell's contents or some other value 1 being shown.
So, I really don't know how to find out exactly why this is happening. Is it that the range I passed is somehow not the right kind? Please inform me of why this code won't work!
I tried to change that line to the comment line below it (and a couple other blind-guess changes), but that has the same error.
Thanks in advance!
Sub redTextToRealDates()
Dim dateTemp As Date
Dim redCell As Range
Dim foundCell As Range
Dim thisSheetsRange As Range
Dim busyCell As Range
Dim redTextCells As Range
Set thisSheetsRange = ActiveSheet.usedRange
'Build a range containing all the cells in a sheet containing red text.
' well... all cells formatted to HAVE red text, anyway.
' Anyone want to tell me how to write this to skip empty cells?
' Because I don't need to grab empty cells into this range...
For Each busyCell In thisSheetsRange
If (busyCell.Font.ColorIndex()) = 3 Then
If redTextCells Is Nothing Then
Set redTextCells = busyCell
Else: Set redTextCells = Union(redTextCells, busyCell)
End If
End If
Next busyCell
'Change unknown format cells to date cells populated with concantenated
'string of original contents and the active sheet's name.
For Each foundCell In redTextCells
foundCell.NumberFormat = "#"
foundCell = GetConcantDate(foundCell)
Next foundCell
redTextCells.NumberFormat = "dd/mm/yy"
On Error Resume Next
End Sub
Function GetConcantDate(rng As Range) As Date
'Original code supplied by ThinkerIV on StackOverflow.com
Dim dtTemp As Date
dtTemp = DateValue(rng.Range("A1").Value & " " & rng.Parent.Name)
'dateTemp = DateValue(foundCell.Value & " " & ActiveSheet.Name)
GetConcantDate = dtTemp
End Function
EDIT
I cant post my own answer yet, so I am adding this solution:
When feeding data to Format(), the contents of the first cell formatted for red were NOT in text form. I had not put in place any way to ensure that I passed the proper data type. So, the line to format the cell as text (foundCell.NumberFormat = "#") before passing it to the function is what fixed it.
The solution was actually already written when I copy/pasted the code into the question - I just wasn't aware that it had fixed it because of another error on a different Sub. (I'm a noob and was confused dealing with multiple errors in multiple subs) I thought I had tried it again with that new line, but HADN'T, so still thought it was not working.
Thanks to all who helped. I feel a bit of a fool now, having found it like that. Hope you forgive me for my rookie flubber - too many Subs and Functions in a huge list in the editor and I got 'dizzy'... At least I can post a solution in case some other noob needs it!
Ok, I think there are two things here. Firstly, the DateValue function takes a string representation of a date, e.g. "01/01/2013", when you pass through an excel date from a range, you are passing through a number, like 41275. This throws the run time error 13.
However, if you already have a date, why bother converting it? You seem to want all red cells to be converted to a date + the sheetname. To do this you'll have to have strings e.g. "01/01/2013 Sheet1", so you couldn't use DateValue here. Instead perhaps try something like this:
Public Function GetConcatDate(rng As Range) As String
Dim dtTemp As String
dtTemp = Format(rng.Range("A1").Value, "dd/mm/yyyy") & " " & rng.Parent.Name
GetConcatDate = dtTemp
End Function

Excel VBA- Lookup cell to paste value to

I'm trying to build a macro that inserts a value into a specific cell of table by looking up a row value and looking up a column value and using that to determine the cell to paste to. I am quite new to VBA so I'm not really sure what I'm doing.
This is what I have so far:
Name=Sheets("Input").Range("C5")
Week=Sheets("Input").Range("C19")
copyCell=Sheets("Input").Range("C18")
pasteCell = Application.Index(Sheets("Resources").Range("B2:AZ50"),Application.Match(Week,Sheets("Resources").Range("A2:A50"),0),Application.Match(Name,Sheets("Resources").Range("B1:AZ1"),0))
copyCell.Copy
pasteCell.PasteSpecial PasteValues
I keep getting a runtime error object required but I'm not quite sure what I'm doing wrong...
Any help would be appreciated!
UPDATE
This is the table which the cell is being pasted too (this table is not the real table just an example so as to hide the names in the table but it looks exactly the same except that the real table starts on the first row).
And this is the input page:
Note: I have since put in more code surrounding the week variable:
If WorksheetFunction.CountA(Sheets("Input").Range("C19")) = 0 Then
Week = Sheets("Input").Range("C20").Value
Else
Week = Sheets("Input").Range("C19").Value
End If
Very much appreciate the help you guys are giving!
without seeing more of your code, I assume you have declared copyCell and pasteCell as Type Variant (if it is not declared, it is type Variant).
This will raise the error you describe.
Resolve it by properly declaring your variables, and using the Set keyword when assigning object variables.
Additionally, failing to declare Name and Week will raise the 424 Object Required error, too. They should be String data type, and assigned using the range .Value method. This error will persist, without more revision to your code, if either of the match functions returns an error (match not found).
I think this will work:
Sub Test()
Dim Name As String
Dim Week As Long
Dim copyCell As Range
Dim pasteCell As Range
Name = Sheets("Input").Range("C5").Value
Week = CLng(DateValue(Sheets("Input").Range("C19").Value))
Set copyCell = Sheets("Input").Range("C18")
If Not IsError(Application.Match(Week, Sheets("Resources").Range("A2:A50"), 0)) And _
Not IsError(Application.Match(Name, Sheets("Resources").Range("B1:AZ1"), 0)) Then
Set pasteCell = Application.Index(Sheets("Resources").Range("B2:AZ50"), _
Application.Match(Week, Sheets("Resources").Range("A2:A50"), 0), _
Application.Match(Name, Sheets("Resources").Range("B1:AZ1"), 0))
copyCell.Copy
pasteCell.PasteSpecial PasteValues
Else:
MsgBox Name & " and/or " & Week & " not found!", vbInformation
End If
End Sub
UPDATED
Excel doesn't always know what to do with date values. that was the case here. On the worksheet, a date value is stored as a long integer. In the macro, we're referring to it as a string, which can raise several errors including '1004' (unable to match).
I made a revision to the code above, Dim Week as Long and then changed the assignment to ensure the value is interpreted as a Date from the worksheet, and then as a Long integer when assigned to this variable:
Week = CLng(DateValue(Sheets("Input").Range("C19").Value))
Now, this may not be foolproof if your dates aren't all actually dates (google it...) but this actually happens pretty often some dates are entered as dates (numbers formatted as date) and others are entered as string literals. If that is the case, the Week value should still be handled properly, but the lookup range also should be formatted the same way to avoid potential errors again.

VBA: How to get the last used cell by VBA code when the last error occured in a Workbook/Worksheet?

Eventually, I want to move the cell to the location where the last error occured. Edit: Forgot to say that I'm using Excel 2003.
As requested in comments...
Look up the 'Caller' property of the 'Application' object in the Excel VBA help. When you use it from a VBA routine, it will tell you where the call to the routine came from - what Range, Chart, etc.
An important thing to be aware of when using 'Application.Caller' is that it isn't always a Range object. Look at the help, but the property returns a Variant value that can be a Range, String, or Error. (It is a Range object in the case you're interested in, but you'll need to be aware of this.)
Because of the above, and the vagaries of VBA syntax when it comes to objects vs. values, it can be tricky to use 'Application.Caller'. Putting a line like:
Debug.Print Application.Caller.Address
in your code will fail when the caller isn't a Range. Doing something like:
Dim v
v = Application.Caller
will "compile", but will create circular references when the caller is a Range because you're trying to access the value of the calling Range.
This all means that it's probably best to write a little utility function for yourself:
Public Function currentCaller() As String
If TypeOf Application.Caller Is Range Then
Dim rng As Range
Set rng = Application.Caller
currentCaller = rng.Address(External:=True)
Else
currentCaller = CStr(Application.Caller)
End If
End Function
and then call it from your error handlers where you want to know where the call came from.
One more thing - obviously this can only tell you the caller once a VBA routine has actually been called. If you have errors in your calling formulas, Excel will return error values to your cells without ever calling your VBA routines.
Wrap your VBA function in another function that stores the cell location and value as variants. Keep this 'wrapper' function as basic as possible so it won't cause any additional errors.
If you're trying to debug app-crashing errors, the wrapper function could even store those values in a comma-delimited text file. Once stored, Excel can crash all it wants and you'll still know what the cell location and value were since you stored them outside of Excel beforehand.
Could this be done with an error handler?
An example of what I mean below:
sub code1()
on error goto cell A1
end sub