Check if value appears in a different worksheet - excel

I have a list. I want to see if it appears in one of the other sheets and return a string dependent on the sheet it is in.
E.g pseudocode:
value = "Hi"
If value in sheet 2 Then
return "Yes"
If value in sheet 3 Then
return "TDB"
Else
return " "
The code I have so far
Public Function Check(product As String) As String
Dim BLRange As Range
Dim xlCell As Range
Dim BL As Worksheet
Dim TBDRange As Range
Dim TBD As Worksheet
Dim result As String
Set BL = ActiveWorkbook.Worksheets("Sheet2")
Set BLRange = BL.Range("A1:A1000")
Set TBD = ActiveWorkbook.Worksheets("Sheet3")
Set TBDRange = TBD.Range("A1:A1000")
For Each xlCell In BLRange
If xlCell.Value = product Then
Check = "Yes"
End If
Next xlCell
For Each xlCell In TBDRange
If xlCell.Value = product Then
Check = "TBD"
End If
Next xlCell
Check = ""
End Function
When I call Check("Hi") I get #VALUE!

Here's a version of the function using find like #urdearboy mentioned...
Public Function Check(product As String) As String
Dim BLRange As Range
Dim TBDRange As Range
Dim fndRng As Range
With ActiveWorkbook
Set BLRange = .Worksheets("Sheet2").Columns("A")
Set TBDRange = .Worksheets("Sheet3").Columns("A")
End With
Set fndRng = BLRange.Find(product)
If Not fndRng is Nothing Then Check = "Yes": Exit Function
Set fndRng = TBDRange.Find(product)
If Not fndRng is Nothing Then Check = "TBD": Exit Function
End Function

Try this code (already tested and works)
Public Function Check(product As String) As String
Dim BLRange As Range
Dim BL As Worksheet
Dim TBDRange As Range
Dim TBD As Worksheet
Dim result As String
Set BL = ActiveWorkbook.Worksheets("Sheet2")
Set BLRange = BL.Range("A1:A1000")
Set TBD = ActiveWorkbook.Worksheets("Sheet3")
Set TBDRange = TBD.Range("A1:A1000")
Check = "none"
For Each xlCell In BLRange
If xlCell.Text = product Then
Check = "Yes"
GoTo a
End If
Next xlCell
For Each xlCell In TBDRange
If xlCell.Text = product Then
Check = "TBD"
GoTo a
End If
Next xlCell
Exit Function
a:
End Function

Related

How to avoid error #NA when executing my macro

I have this error with my macro. My macro takes data from a table and in another sheet, outputs in a table my data for each value of a third sheet.
So let's say my table's value are : Jack and Daniel. And on my third sheet, I have Football and Rugby. The output in the second page will be :
Jack Football
Jack Rugby
Daniel Football
Daniel Rugby
Here is my macro :
Sub yo()
Dim Letters, Chk, Ele As Range, i As Long: Letters = Sheets("Sports").Range("C3:C5").Value
For Each Ele In Sheets("Students").ListObjects(1).ListColumns(1).DataBodyRange
With Sheets("OK").ListObjects(1)
Chk = Application.Match(Ele, .ListColumns(1).Range, 0)
If IsError(Chk) Then
For i = 1 To 3
.ListRows.Add.Range = Array(Ele, Letters(i, 1))
Next i
End If
End With
Next Ele
End Sub
However this works fine. The problem comes from all the other columns of the table in my second sheet. They all get the value "#NA". So instead of having nothing or formulas expanding down, there is that error.
How can I overcome this error ?
Copy to Excel Table (ListObject)
The short answer is that in this case a ListRow has four columns yet you're assigning it an array of only two. By the looks of your answer, you have concluded this yourself (.Resize(, 2)).
An Improvement
Option Explicit
Sub AddStudents()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim wsSports As Worksheet: Set wsSports = wb.Sheets("Sports")
Dim Sports(): Sports = wsSports.Range("C3:C5").Value
Dim SportsCount As Long: SportsCount = UBound(Sports, 1)
Dim wsStudents As Worksheet: Set wsStudents = wb.Sheets("Students")
Dim loStudents As ListObject: Set loStudents = wsStudents.ListObjects(1)
Dim lcStudents As ListColumn: Set lcStudents = loStudents.ListColumns(1)
Dim rgStudents As Range: Set rgStudents = lcStudents.DataBodyRange
Dim wsOK As Worksheet: Set wsOK = wb.Sheets("OK")
Dim loOK As ListObject: Set loOK = wsOK.ListObjects(1)
Dim lcOK As ListColumn: Set lcOK = loOK.ListColumns(1)
Dim rgOK As Range: Set rgOK = lcOK.DataBodyRange
Dim cell As Range, Student, MatchOK, r As Long, IsNotStudentAdded As Boolean
For Each cell In rgStudents.Cells
If rgOK Is Nothing Then
IsNotStudentAdded = True
Else
MatchOK = Application.Match(cell.Value, rgOK, 0)
If IsError(MatchOK) Then IsNotStudentAdded = True
End If
If IsNotStudentAdded Then
Student = cell.Value
For r = 1 To SportsCount
loOK.ListRows.Add.Range.Resize(, 2).Value _
= Array(Student, Sports(r, 1))
Next r
IsNotStudentAdded = False
Set rgOK = lcOK.DataBodyRange
End If
Next cell
MsgBox "Students added.", vbInformation
End Sub
So I decided to completely change my macro to avoid any error :
Sub Macro7()
Dim N, S, i, j
Application.ScreenUpdating = False
N = Range("Tableau1"): S = Sheets("Sports").Range("C3:C5").Value
With Range("Tableau2").ListObject
If .ListRows.Count > 0 Then .DataBodyRange.Delete
For Each i In N
For Each j In S
.ListRows.Add.Range.Resize(, 2) = Array(i, j)
Next
Next
End With
End Sub

how to find multiple strings using range.value?

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

Excel VBA - UDF returns 0 or empty or #value

I am creating my customized function. I wrote the code and tested it as “sub and it worked well. Then i converted it into a function to be able to use it in general. Things that i changed are; adding a function declaration, taking input from excel cell and specifying function output. All others remained same.
My function only has one input which is a selected cell from an excel sheet. And i expect that function returns one output. However, it returns 0.
• function declaration. "Function IbpBomLevel(ByVal Target As Range) As Variant
• input of function as selected cell. "ProductID = Target
• output of function. "IbpBomLevel = fullText
I used option explicit to avoid non-exist functionalities. Also, I am sure about the input, function really takes the selected cell as input. But the problem is that in each loop “ProductID must be changed. Hovewer, when i declared that "IbpBomLevel (output of the function) = ProductID and saw that ProductID is the first parameter that user selected from a cell. It means loop not works. When i test it as “sub, i got the result that i want. I am not sure what the problem is.
Option Explicit
Function IbpBomLevel(ByVal Target As Range) As Variant
Dim Wb As Workbook
Dim Ws As Worksheet
Dim MyRange As Range
Dim SourceID As Variant
Dim SourceID2 As Variant
Dim SourceID3 As Variant
Dim Product As Variant
Dim Item As Variant
Dim Location As Variant
Dim Resource As Variant
Dim I As Variant
Dim T As Variant
Dim Z As Variant
Dim X As Variant
Dim Y As Variant
Dim Index As Variant
Dim Index2 As Variant
Dim Index3 As Variant
Dim BomLevel As Variant
Dim FoundCell As Variant
Dim fullText As Variant
Dim ProductID As Variant
ProductID = Target
Set Wb = Workbooks("Kitap.xlsx")
Windows("Kitap.xlsx").Activate
On Error GoTo T_Error
Set Ws = Wb.Worksheets("Production Source Header")
Sheets("Production Source Header").Select
Set MyRange = Worksheets("Production Source Header").Range("B:C")
SourceID = CVar(Application.WorksheetFunction.VLookup(ProductID, MyRange, 2, False))
I = 1
T = 0
Z = 1
If IsEmpty(SourceID) = False Then
Do While (IsEmpty(SourceID) = False) And (T = 0)
BomLevel = Z
Windows("Kitap.xlsx").Activate
Set Ws = Wb.Worksheets("Production Source Header")
Sheets("Production Source Header").Select
Set MyRange = Worksheets("Production Source Header").Range("B:C")
SourceID = CVar(Application.WorksheetFunction.VLookup(ProductID, MyRange, 2, False))
Set FoundCell = ActiveSheet.Range("C:C").Find(What:=SourceID)
If Not FoundCell Is Nothing Then
Index = FoundCell.Row
Location = Cells(Index, 1)
Product = Cells(Index, 2)
Else
End If
X = I
I = I + 1
Windows("Kitap.xlsx").Activate
Set Ws = Wb.Worksheets("Production Source Item")
Sheets("Production Source Item").Select
Set MyRange = Worksheets("Production Source Item").Range("B:B")
SourceID2 = CVar(Application.WorksheetFunction.VLookup(SourceID, MyRange, 1, False))
Do While (IsEmpty(SourceID2) = False) And (I - X = 1)
Set MyRange = Worksheets("Production Source Item").Range("B:B")
SourceID2 = CVar(Application.WorksheetFunction.VLookup(SourceID, MyRange, 1, False))
Set FoundCell = ActiveSheet.Range("B:B").Find(What:=SourceID2)
If Not FoundCell Is Nothing Then
Index2 = FoundCell.Row
Item = Cells(Index2, 1)
Windows("Kitap.xlsx").Activate
Set Ws = Wb.Worksheets("Production Source Header")
Sheets("Production Source Header").Select
Else
End If
Y = I
I = I + 1
Windows("Kitap.xlsx").Activate
Set Ws = Wb.Worksheets("Production Source Resource")
Sheets("Production Source Resource").Select
Set MyRange = Worksheets("Production Source Resource").Range("B:B")
SourceID3 = CVar(Application.WorksheetFunction.VLookup(SourceID, MyRange, 1, False))
Do While IsEmpty(SourceID3) = False And (I - Y = 1)
Set MyRange = Range("B:B")
SourceID3 = CVar(Application.WorksheetFunction.VLookup(SourceID, MyRange, 1, False))
Set FoundCell = ActiveSheet.Range("B:B").Find(What:=SourceID3)
If Not FoundCell Is Nothing Then
Index3 = FoundCell.Row
Resource = Cells(Index3, 1)
Windows("Kitap.xlsx").Activate
Set Ws = Wb.Worksheets("Production Source Header")
Sheets("Production Source Header").Select
Else
End If
I = I + 1
Loop
Loop
fullText = fullText & " Location: " & Location & " // Header: " & Product & " // Item: " & Item & " // Resource: " & Resource
Z = Z + 1
ProductID = Item
Set MyRange = Worksheets("Production Source Header").Range("B:C")
SourceID = (Application.WorksheetFunction.VLookup(ProductID, MyRange, 2, False))
T_Error:
If Err.Number = 1004 Then
On Error Resume Next
T = 1
Else
End If
Loop
IbpBomLevel = fullText
Else
MsgBox ("Bom Missing")
End If
End Function

' Range.Find' and ' Range.FindNext' to loop only over the first match

I am looping through a set of data with VBA Excel. I am trying to find a certain string using a combination the Range.Find and the Range.FindNext methods. I having a hard time figuring out where to place these statements because I need them to be in the scope of each other but at the same time I don't want the first Find statement to keep executing every time, hence only looping over the first match.
Sub AssignGroups()
Dim membership As Worksheet
Dim wb As Workbook
Dim groups As Worksheet
Dim nameRow As Long
Dim fullNameString As String
Dim nameRange As Range
Dim groupRange As Range
Dim nameRange2 As Range
Dim nameIndex As Long
Dim userNameString As String
Dim barIndex As Long
Set wb = ActiveWorkbook
Set membership = Sheets("User Group Membership")
Set groups = Sheets("User Assigned to Groups")
Set nameRange = membership.Range("A:A").Find("user -name", Lookat:=xlPart)
If Not nameRange Is Nothing Then
firstAddress = nameRange.Address
Set nameRange = membership.Range("A:A").Find("user -name", Lookat:=xlPart)
Do
membership.Activate
nameRow = nameRange.Row
MsgBox (nameRow)
fullNameString = membership.Cells(nameRow, "A").Value
MsgBox (fullNameString)
nameIndex = InStr(fullNameString, "user -name")
barIndex = InStr(fullNameString, "|")
MsgBox (nameIndex)
MsgBox (barIndex)
userNameString = Mid(fullNameString, nameIndex + 12, ((barIndex - 4) - (nameIndex + 12)))
groups.Activate
Set nameRange2 = groups.Range("A:CH").Find(userNameString)
nameColumn = nameRange2.Column
membership.Activate
membership.Cells(nameRow, "A").Activate
Do
ActiveCell.Offset(1).Activate
If Not IsEmpty(ActiveCell.Value) Then
cellValue = ActiveCell.Value
groups.Activate
Set groupRange = groups.Range("A:CH").Find(cellValue, , , Lookat:=xlWhole)
groupRow = groupRange.Row
groups.Cells(groupRow, nameColumn).Activate
ActiveCell.Value = "X"
membership.Activate
End If
Loop Until IsEmpty(ActiveCell.Value)
Set nameRange = membership.Range("A:A").FindNext(ActiveCell)
Loop While Not nameRange Is Nothing And nameRange.Address <> firstAddress
End If
End Sub
How could I place these statements so that it would loop over all the matches, one after another?

I'm trying to get a value to enter in a specific first cell/row. My forumula is:

Sub CheckBox7_Click()
Dim cBox As CheckBox
Dim LRow As Integer
Dim LRange As String
LName = Application.Caller
Set cBox = ActiveSheet.CheckBoxes(LName)
'Find row that checkbox resides in
LRow = cBox.TopLeftCell.Row
LRange = "B" & CStr(LRow)
'Change text in column b, if checkbox is checked
If cBox.Value > 0 Then
ActiveSheet.Range(LRange).Value = "3300-0401"
'Clear text in column b, if checkbox is unchecked
Else
ActiveSheet.Range(LRange).Value = Null
End If
End Sub
I need value 3300-0401 to be entered in the first available cell beginning at b15 through b40. Also, where would this date be entered in the string?
Thanks, Jean
You can use the following to write to the first blank cell in the range B15:B40:
Sub WriteToFirstAvailableCellInRange()
Dim wb As Workbook
Dim ws As Worksheet
Dim firstEmptyCell As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
If ws.Range("B15").Value = "" Then
Set firstEmptyCell = ws.Range("B15")
Else
If ws.Range("B16").Value = "" Then
Set firstEmptyCell = ws.Range("B16")
Else
Set firstEmptyCell = ws.Range("B15").End(xlDown).Offset(1)
End If
End If
If firstEmptyCell.Row < 41 Then
firstEmptyCell.Value = "3300-0401"
Else
MsgBox "There aren't any empty cells in range B15:B40."
End If
End Sub

Resources