VBA Vlookup not finding values that exist - excel

I am working with two different Worksheets in one workbook. My task is to look up the model# of a product from Sheet1, find that same model# in Sheet2, and get the cost of that product, which is located a few columns away.
So naturally, I tried to use Vlookup, because that function is enough for this query.
I will post my code below, and then explain the problems I am facing. I am new to VBA and have searched many many different Stack posts, and tried the various solutions, to no avail.
Private Sub CommandButton1_Click()
Dim tbdCell As Range
Dim model As Range
Dim cell As Range
Dim PAsheet As Worksheet
Dim DB As Worksheet
Dim target As Variant
Set DB = Worksheets("Database")
Set PAsheet = Sheets("Pricing Agreement")
Set tbdCell = Range("N2:N4700")
On Error GoTo ErrHandler:
For Each cell In tbdCell
Set model = cell.Offset(0, -6)
cell = WorksheetFunction.VLookup((CStr(model)), PAsheet.Range(CStr("C2:D2000")), 6, True)
Next cell
Exit Sub
ErrHandler:
Select Case Err.Number
Case 0
Case 1004
cell = "missing"
Resume Next
Case Else
MsgBox Err.Number & vbNewLine & Err.Description
Exit Sub
End Select
End Sub
So upon debugging and testing, most things work until we get to the line where I use the Vlookup function. I invariably get error 1004, even though the data exists in the other spreadsheet. So the cells that I need to fill will always fill with "missing" as posted above in the Error Handling Code.
I tried using the Application version of the function. I tried using different variables and declaring them as Variant type. I even tried making the table_array range just one row with 2 column coverage, in an attempt to force a match for one particular model #. So far, to avoid a type mismatch, I cast 'model'(the model#) into a String, and I also cast the search range in PAsheet to String. The final thing I tried was to not search for an exact match(last argument was set to true)
So in anticipation of future questions about the data that the Vlookup is based on, I will include necessary information about how both sheets are formatted.
Info that you may need:
We start in column N, where the prices are missing in Sheet1(Database).
I set model to the value in the same row, 6 columns to the left(Column H).
Testing with MsgBox proved this to work for me, and on debug, the model variable displays the correct info, so this isn't the issue.
In PAsheet, the model #s are in column C. Originally I made the search table from C2:C2000 or so, but I was led to believe that you need at least a two column table for Vlookup to work, so I changed C2000 to D2000. Now the search range is a two column table.
In PAsheet, the cost of the product is in Column H, which is 5 away from column C. I need this value, so I put 6 in the column_index argument. It was 5 before, because I thought that you didn't count the first column, but I fixed that.
Finally I mostly tested with "False" as the last argument, but either way it doesn't work.
So after trying more than two dozen variations and strategies, I still get "missing" in the cells that I need to fill.
So, what am I doing wrong here? Thanks in advance.

If you are trying to return the 6th value from Column C your range needs to be updated to `PAsheet.Range("C2:H2000")
cell.Value = WorksheetFunction.VLookup(cell.Offset(, -6), PAsheet.Range("C2:H2000"), 6, False)

Related

Run-time Error 1004 while adding table rows

I am trying to use the following code to add rows to a table. I need the number of rows to be dynamic because I am adding rows from one table to my main table, and the number of rows in the supplementary table can vary.
Currently, cell F2 counts the number of rows in the supplementary table, and this is supposed to be how many rows the macro adds to my main table. However, when referencing the RowNumber variable, I receive the error message "Insert method of range class failed".
I tried replacing the variable with different numbers, and then the code runs fine. However, whenever I use the variable, I get the error message.
Appreciate any help.
Sub AddRows()
Dim ws As Worksheet
Dim RowNumber As Range
Set ws = ThisWorkbook.ActiveSheet
With ws
Set RowNumber = .Range("F2")
Range("A8").End(xlDown).Select
ActiveCell.EntireRow.Resize(RowNumber.Value).Insert Shift:=xlDown
End With
Range("tblDetail").Select
Range("A10").Activate
Selection.FillDown
End Sub
EDIT: I think I am receiving the error because I have a table which starts three rows below my main table (this is an import file for online accounting software, which requires a certain number of tables). I played around with the value in F2: anything greater than "4" in F2 results in the 1004 error (assuming the active cell when the macro is run is in the last row of my main table). Anything less than 4, and the code runs fine.
Is there maybe a way to use variables with the listrows.add function, since my main table is a list object?
Try This:
ActiveCell.EntireRow.Resize(CInt(RowNumber.Value)).Insert Shift:=xlDown
I was able to reproduce your error in my own spreadsheet. Range("F2").Value was returning a string value when F2 contained the formula =ROWS(Table1). The conversion fixed it for me.
Revised Answer
The following code will append the number of rows specified in F2 to the table in which A8 resides:
Dim insertIndex As Integer
Dim insertPosition As Integer
With Range("A8")
insertPosition = .Row - .ListObject.Range.Row
With .ListObject.ListRows
For insertIndex = 1 To CInt(Range("F2").Value)
.Add
Next
End With
End With
That works even if there is a table immediately below the table in which A8 resides.

Looping through cells within multiple tables and changing value if font color =

I have a spreadsheet that has 3-6 tables in it. I need to use a macro that will change a value from say "30" to "'30" if any of the cells within the row are red. This is because red rows are cancelled reservations; we still need the value and I don't want my other formulas to count that number as a valid number (since it's not an actual reservation.) I've perused many articles with options but usually these articles have a range that is set with a specific table name. Since there are multiple tables, the tables change and I don't know how to make it dynamic. Furthermore, I don't want to have to update the macro each time. If I can circumvent naming the particular tables, my code could work on each sheet (sheets change monthly). One of the issues with my code is that the value I need to change is always in column J. My current code, I imagine, would see the whole row as needing to be changed. I currently get a Run-time error 6: Overflow.
Option Explicit
Sub LoopThroughAllTablesInWorksheet()
Dim tbl As ListObject
Dim Cell As Range
Dim OldValue As Integer
For Each tbl In ActiveSheet.ListObjects
For Each Cell In tbl.DataBodyRange
If Cell.Font.Color = RGB(255, 0, 0) Then
OldValue = Cell.Value
Cell.Value = "'" & OldValue
End If
Next Cell
Next tbl
End Sub
I used the following to help me get where I am: http://www.TheSpreadsheetGuru.com/the-code-vault
https://www.thespreadsheetguru.com/blog/2014/6/20/the-vba-guide-to-listobject-excel-tables
I was able to make this work by changing the line "For Each Cell In tbl.DataBodyRange" to "For Each Cell In tbl.ListColumns(10).Range".

excel vba range.find not finding date

I'm trying to establish the minimum date and its associated row for later use in a subroutine.
I'm hitting an error and i've spent the last few hours isolating the issue and searching for the solution to no avail.
I have a spreadsheet where column B contains a range of dates arranged in order. I can find the minimum date (the message box correctly returns 11/14/2015), but when I try use that date value to identify the row number I get error 91. Here is my code:
Sub testing()
ThisWorkbook.Worksheets("Burn Curve Data").Activate
Dim rDateColumn As Range
Dim dMinDate As Date
Set rDateColumn = ActiveSheet.Range("B:B")
dMinDate = Application.WorksheetFunction.Min(rDateColumn)
MsgBox dMinDate
Dim rMinCell As Range
Dim intMinRow As Integer
Set rMinCell = rDateColumn.Find(dMinDate, LookIn:=xlValues, LookAt:=xlWhole)
intMinRow = rMinCell.Row
MsgBox intMinRow
End Sub
I tried inserting an If Not statement after Set rMinCell and determined that range.find is not finding the date. Here is the statement I used to identify the error, but I deleted it to clean up the code for this posting.
If Not rMinCell is Nothing Then
intMinRow = rMinCell.Row
Else
MsgBox "error finding rMinCell"
End If
I also tried re-saving dMinDate into a string then using that string in the range.find but I encountered the same error of not finding the date.
Another nuance that may or may not be relevant is that this data exists within a named range on the worksheet. What am I doing wrong with my range.find line?!?
As discussed in the comments it appears the issue arises when the column is formatted as something other than Date.
To do this via code you can add this line after you set the rDateColumn variable:
rDateColumn.NumberFormat = "m/d/yyyy"
This should format the column as a date and your Find method should work appropriately.
Alternatively you can select the column, click 'Format Cells' and then ensure 'Date' is selected under Category.

How to use one column in excel as a search parameter in another column to output only certain strings

This question stems off another post I had. (see Search through column in excel for specific strings where the string is random in each cell)
Using the above image as reference, I am trying to search through column B (actually over 1000 lines) using column E as the "lookup values." The end goal would be for "just" the names to be displayed in column C. The trick is all the randomly generated characters the encompass the names. Below is what I would want the datasheet to look like. A formula or module should work, but the vlookup and other lookup function I can't get to work.
For a worksheet function approach, you could enter in C3 and fill down this formula:
=LOOKUP(8^5,SEARCH(E$3:E$7,B3),E$3:E$7)
The constant 8^5=32768 is chosen to be larger than the maximum possible string length so that LOOKUP returns the last matching value. The formula returns #N/A if no string is found.
Another possibility, which may be easier to understand then assylias post initially, but also may be a bit more time consumptive (although with 1,000 rows, I don't think it will matter much) is below.
This requires that you name the range in column E as myNames (or whatever name you wish, just update the code - alternatively, you cuold just write Range("E1:E6")). Also, if you move the random values from column B, update that in the code as well.
Sub findString()
Dim celString As Range, rngString As Range, celSearch As Range, rngSearch As Range
Dim wks As Worksheet
Set wks = Sheets("Sheet1") 'change sheet reference to whatever your sheet name is
Set rngString = wks.Range("myNames")
Set rngSearch = Intersect(wks.UsedRange, wks.Range("B1").EntireColumn)
For Each celString In rngString
For Each celSearch In rngSearch
If InStr(1, celSearch.Text, celString.Value) > 0 Then
celSearch.Offset(, 1) = celString.Value
End If
Next
Next
End Sub
Since, I worked on your original question as well, I would suggest getting the counts through Siddharth's answer and then running this, or assylias's code above to get the names next to the columns. You could put a button the sheet, or just use the Macro dialog box to run the macro.

Populating a list box with data from worksheet

I currently get the following error when I run the code (shown below)
Type Mismatch
To give a bit of context, the worksheet CourseSelection has row 3 populated from A to F. I would like to put the entries from A2:A6 into a listbox. However, I want to generalize this process and make it dynamic to include additional categories if they are added after column F. Therefore I need an automatic way to do this through code similar to what I have below. However, I am getting error messages and I am unsure why.
I defined TaskList as a Range prior to this code. When I hover over xlToRight when I run the code I see a very large negative value (-4191). I am unsure if this is part of the problem.
With Worksheets(CourseSelection).Range("A3")
Set TaskList = Range(.Offset(0, 1), .End(xlToRight))
End With
frmTaskSelection.lbTasks.RowSource = TaskList
Unless you have CourseSelection defined as a constant returning an existing worksheet name then the code will fail on With Worksheets(CourseSelection).Range("A3"). If you want to work with a sheet name CourseSelection you would use With Worksheets("CourseSelection").Range("A3").
Given you error message though you appear to have gotten past this point and your code appears to be failing on frmTaskSelection.lbTasks.RowSource = TaskList. This is because RowSource expects an address
If you were looking to populate the values from a sheet called CourseSelection from A3 to Ax where x is the last used cell, then this code will work from any active sheet.
Please note thate I was unclear as to how you wanted to use further values from column F in addition to A2:A6. If you can provide further guidance/picture etc then the code below can be adapted to suit
Sub test()
Dim ws As Worksheet
Dim rng1 As Range
Set ws = Worksheets("CourseSelection")
Set rng1 = ws.Range(ws.[a3], ws.Cells(Rows.Count, "A").End(xlUp))
frmTaskSelection.lbTasks.RowSource = "'" & ws.Name & "'!" & rng1.Address
frmTaskSelection.Show
End Sub

Resources