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.
Related
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.
I have this code which is causing a mismatch error and I can't figure out why I had it working sort of before with the mismatch error and in an attempt to fix it I can't get it back to working. The values in the merge sheet are all numeric. Basically what I was trying to do was when a value is entered into a cell there would be a VLookup would be executed to input a value into the adjacent cell and once I get this working, more cells in the same row. If any of you are itching to fix something just let me know!
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim LooupValue As String
Dim sfx As Long
Set KeyCells = Columns(1)
LooupValue = ActiveCell.Value
sfx = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
Range(Target.Address).Offset(0, 1).Value = sfx
End If
End Sub
Edit: Thanks to #Marcucciboy2, #MathieuGuindon, and #BigBen for their successful help, I have done some more research and posted what solved my issue down below.
Dim sfx As Long
sfx = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
If the vlookup yields xlErrNA i.e. #N/A, then VBA can't coerce its result into a Long, and you get exactly that: a type mismatch error - because xlErrNA is an Error value, which can't be implicitly converted to a String, a Long, or anything. The only type that can contain this data, is a Variant.
Dim result As Variant
result = Application.VLookup(LooupValue, Worksheets("Merge").Range("D:BD"), 2, False)
Dim sfx As Long
If Not IsError(result) Then
sfx = CLng(result)
Else
'lookup yielded no match
End If
Also, it looks like this is off-by-one:
LooupValue = ActiveCell.Value
The ActiveCell likely isn't the same cell as Target, which is the cell that was modified. You probably need this instead:
LookupValue = Target.Value
I'd also recommend making unqualified Range (same with Rows, Colomns, Names, and Cells) calls explicitly qualified - because that exact same code behaves differently depending on where it's written in. By qualifying them with Me, you're making your code more explicit. Code that says what it does, and does what it says, is always better code.
Worksheets("Merge") is a smell: if the sheet exists in ThisWorkbook at compile-time, give it a code name (i.e. set its (Name) property) and use that identifier directly:
result = Application.VLookup(LooupValue, MergeSheet.Range("D:BD"), 2, False)
If the sheet only exists at run-time (e.g. it's in a workbook that was opened by the macro), then you should have a reference to that workbook near where you opened that file, e.g. Set book = Application.Workbooks.Open(path) - use that reference to qualify the Worksheets member call, instead of implicitly referring to ActiveWorkbook.
The lookup range D:DB is excessive when you're only looking for the value in column E. If that hard-coded 2 is there to stay, I'd make the lookup range be D:E.
I would also nest the value setting within the "If" that checks for intersection; otherwise, every time you change the worksheet it does an unnecessary vlookup in the background.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("A:A")) Is Nothing Then
Target.Offset(0, 1).value = Application.VLookup(Target.value, Worksheets("Merge").Range("D:BD"), 2, False)
End If
End Sub
I figured out what the last problem was... The lookup column was, for some reason from the previous document editor, formatted as text. The reason why only some lookup values were working was because even after I formatted the entire column to numbers, the said values were reformatted as numbers only after I had edited the cell. I wasn't going to edit every single cell so I did some research and found out how to refresh an entire column's format.
I refreshed the column by doing the following:
Select the entire column
Format the column as necessary
Go to the Data ribbon and select 'Text-to-Columns'
Ensure Delimited is selected, click Next
Uncheck all the Delimiters, click Next, then Finish
When I try this code an error comes up saying "Run Time Error '424': Object Required"
I can see that it finds the inputted number, but doesn't copy any number in the row. It also pastes "0" in the wrong sheet.
Here's my code:
Dim x As Integer
Dim a As Integer
Dim b As Integer
x = InputBox(("Input palletizer pattern."), ("Pattern"), (0))
Application.Goto ThisWorkbook.Sheets("Palletizer 2").Range("A:A").Cells(Application.Match(x, ThisWorkbook.Sheets("Palletizer 2").Range("A:A")))
With Selection
ActiveCell.Offset(0, 3) = a
Set ThisWorkbook.Sheets("Palletizer Changeover App").Range("I6") = a
End With
Any help would be much appreciated.
You are getting the error because you use a set statement to assign the integer a to the range I6. You can only use set statements to assign objects.
The error will go away if you remove the Set in the second last line. However, please note that it would be more obvious what you are trying to achieve if you explicitly assigned to the Value property of the range, which its default property.
With why the number does not appear at the right spot I cannot help you because your exact intentions are not clear to me from your question.
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).
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