I want to find out if a particular group of cells match another group of cells in a different sheet using VBA. In my case, I need to find out if the lastName, firstName cells match. In my solution that I came up with, I'm looping through the first table, getting the employee name. Then looping through the second table, getting the employee name. Then seeing if the two match up. This method is too costly and takes too long. Is there any better way to do this?
My first table contains 6 rows, my second table can contain 100+ rows. Too much time is wasted.
I was thinking about just searching down the entire column to see if the last name matches first, if it does, then go and see if the first name matches... but then again, there could be some people with the same last name..
Here is what I have so far.
For i = 2 To managerRows 'Looping through the Managers Table
empFirst = managerSheet.Cells(i, 1)
empLast = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
For j = 3 To assignRows 'Looping through the Assignments table
empLastAssign = assignSheet.Cells(i, 4)
empFirstAssign = assignSheet.Cells(i, 5)
empNameAssign = (empLastAssign & ", " & empFirstAssign)
'MsgBox (empNameAssign)
...
Conditional statement comparing names
...
Next j
Next i
I know I have no conditional statement, I didn't bother writing it because I knew this approach is not the best one.
I cannot add another column to concatenate the second sheets names because they are read from a database and kept in separate columns and last name and first name. Anyways, is there a way that I can concatenate the names without adding another column to the second sheet and try to find them that way? Does that make sense?
Find will only look in one column if I'm not mistaken. Can it look in two?
UPDATE
I'm able to get the first occurrence of the last name, but not the others. I've added another field to match. So there are three fields to match now. Last Name, First Name, and Project Name. So far, my code will only find the first occurrence and stay there. I think my order of the looping is wrong.
Here is what I have so far.
For i = 2 To managerRows 'Looping through the Managers Table
empLast = managerSheet.Cells(i, 1)
empFirst = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
projectName = managerSheet.Cells(i, 3)
managerLast = managerSheet.Cells(i, 4)
managerFirst = managerSheet.Cells(i, 5)
managerName = (managerLast & ", " & managerFirst)
Set findRow = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)) 'Set a range to look for Last Name
Set c = findRow.Find(empLast, LookIn:=xlValues) 'Find matching Last Name if it exists
If Not c Is Nothing Then 'Last Name found
Do Until c Is Nothing 'Is this in the wrong place?
If Cells(c.Row, 5) = empFirst Then 'If first name matches
If Cells(c.Row, 10) = projectName Then 'If project name matches. We found them
MsgBox ("Found: " & empLast & ", " & empFirst & ": Project: " & projectName & " : in: " & c.Row)
End If
End If
Set c = findRow.FindNext(c) 'Is this is the wrong place?
Loop
End If
Set c = Nothing 'Is this in the wrong place?
Next i
Take a look at 'Is this in the wrong place? for my new loop.
UPDATE 2: Solved
I have successfully filtered on three columns using find and findNext. With the help of some good answers. I will post the completed version. I had to add extra else statement into my filters in order to go to the next ling found. Hopefully others can learn from this, as there is no clear answer for filtering on three columns using find.
For i = 2 To managerRows 'Looping through the Managers Table
empLast = managerSheet.Cells(i, 1)
empFirst = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
projectName = managerSheet.Cells(i, 3)
managerLast = managerSheet.Cells(i, 4)
managerFirst = managerSheet.Cells(i, 5)
managerName = (managerLast & ", " & managerFirst)
'Focus Below this
Set findRow = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)) 'Set a range to look for Last Name
Set c = findRow.Find(empLast, LookIn:=xlValues) 'Find matching Last Name if it exists
If Not c Is Nothing Then 'Last Name found
Do Until c Is Nothing
If Cells(c.Row, 5) = empFirst Then 'If first name matches
If Cells(c.Row, 10) = projectName Then 'If project name matches. We found them
MsgBox ("Found: " & empLast & ", " & empFirst & ": Project: " & projectName & " : in: " & c.Row)
Set c = Nothing
Else
Set c = findRow.FindNext(c)
End If
Else
Set c = findRow.FindNext(c)
End If
Loop
End If
Next i
Instead of using two loops, you can use just the first one and utilize the find function. I believe it'll be faster for you.
For i = 2 To managerRows 'Looping through the Managers Table
empFirst = managerSheet.Cells(i, 1)
empLast = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
managerLast = managerSheet.Cells(i, 3)
managerFirst = managerSheet.Cells(i, 4)
managerName = (managerLast & ", " & managerFirst)
MsgBox (empName & ", " & managerName)
Set myRng = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)
Set c = myRng.Find(empName, lookin:=xlValues)
if Not c is Nothing Then 'you found last name, no look to see if first is a match
if assignSheet.cells(c.row, 5) = empFirst then 'if it is, do something
'do whatever you need to do here
else
firstAddress = c.Address
Do
Set c = myRng.FindNext(c)
if Not c is Nothing Then 'you found last name, no look to see if first is a match
if assignSheet.cells(c.row, 5) = empFirst then 'if it is, do something
'do whatever you need to do here
end if
end if
Loop While Not c Is Nothing And c.Address <> firstAddress
end if
end if
Next i
For more information on find, look here.
you only need to know if it is there... then use COUNTIFS like:
=COUNTIFS(A:A,"Name",B:B,"Lastname"....)
and if it is not 0 then there is a match.
For VBA it is
Application.Countifs(Range("A:A"),"Name",Range("B:B"),"Lastname"....)
If you have any questions left, just ask ;)
EDIT
... I need the row number that they exist in ...
You never said that! *angry face*... still, it is possible to do in a more or less fast way:
Sub test()
Dim val As Variant, rowNum As Variant
With Sheets("Sheet1")
val = Evaluate(Intersect(.Columns(1), .UsedRange).Address & "&"" --- ""&" & Intersect(.Columns(2), .UsedRange).Address)
rowNum = Application.Match("name" & " --- " & "firstname", val, 0)
If IsNumeric(rowNum) Then Debug.Print "Found at Row: " & rowNum Else Debug.Print "Nothing was found"
End With
End Sub
I usually use a dictionary or collection when looking for duplicates. In this way I only have to loop through each list one time.
Sub FindDuplicates()
Dim empFirst As String, empLast As String, empName As String
Dim assignSheet As Worksheet, managerSheet As Worksheet
Dim i As Long, lastRow As Long
Dim d
Set assignSheet = Sheet2
Set managerSheet = Sheet1
Set d = CreateObject("Scripting.Dictionary")
With managerSheet
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastRow 'Looping through the Managers Table
empFirst = .Cells(i, 1)
empLast = .Cells(i, 2)
empName = (empLast & ", " & empFirst)
If Not d.exists(empName) Then d.Add empName, i
Next
End With
With assignSheet
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastRow 'Looping through the Managers Table
empFirst = .Cells(i, 4)
empLast = .Cells(i, 5)
empName = (empLast & ", " & empFirst)
If d.exists(empName) Then
Debug.Print "Match Found", empName, "assignSheet Row:" & i, "managerSheet Row:" & d(empName)
End If
Next
End With
End Sub
Related
I'm kind of struggeling with VBA for excel. I have a table with products, where products can have multiple categories. The categories that are linked to a product can have sub-categories, which are located in the columns next to it. If a product has multiple categories, these categories are located one row below the product. See pic1.
What I want to achieve:
Every time I execute the script, the current categories that are on the row of the product info need to be replaced with the categories below it, until you reach the next product. If there is no new category to replace, the product row can be deleted. (In this example I need to run the script 3 times). So I eventually will end up with this:
Run script first time:
Run script second time:
Run script 3rd time:
The code I've got so far is:
Sub MoveEmpty()
Dim i as Long, j as Long
Application.ScreenUpdating = False
j = Range("A" & Rows.Count).End(xlUp).Row
For i = j to 3 Step -1
If Range("A" & i) <> "" Then
Range("C" & i -1) = Range("C" & i).Resize(,3)
Range("A" & i).EntireRow.Delete
End If
Next i
End Sub
Hope this makes sense, and thanks for helping out,
Bart
You were on the right track, this should do what you want:
Sub MoveEmpty()
Dim i As Long, j As Long
Dim ws As Worksheet
Application.ScreenUpdating = False
' Set this appropriately
Set ws = ThisWorkbook.Worksheets("MyWorksheet")
j = ws.Range("A" & Rows.Count).End(xlUp).Row
For i = j To 3 Step -1
If ws.Range("A" & i) <> "" Then
' Copy the product name to be next to the 2nd category set down, if there is a category
If ws.Range("A" & (i + 1)) = "" And ws.Range("C" & (i + 1)) <> "" Then
' If you just want the values (i.e. no formatting copied)
ws.Range("A" & (i + 1)).Resize(, 2).Value = ws.Range("A" & i).Resize(, 2).Value
' If you want everything, including formats
Call ws.Range("A" & i).Resize(, 2).Copy(ws.Range("A" & (i + 1)).Resize(, 2))
End If
ws.Range("A" & i).EntireRow.Delete
End If
Next i
' Reset the screen to updating
Application.ScreenUpdating = True
End Sub
My goal is to name my just-pasted range something unique to I can find it in the future.
The copied and pasted range comes from a drop-down menu, and thus must be modified
Selection.Name.Formula = "=""AddSection_""&SUBSTITUTE('Add Section'!D3,"" "","""")"
If they select Oil Furnace in D3's drop down, then that section is copied and pasted. It should be named "AddSection_OilFurnace"
Is this possible?
What I would REALLY love is if I could have a named range that updates based on how many exist before it. For example, the above would be "AddSection_OilFurnace1" and the next section would be "AddSection_GasFurnace2" and so on. But I have no idea how or if that is possible haha. Would it be something like:
Worksheets("Add Section").ranges.count
Is that possible and how would it go into my naming formula?
I'm super new to VBA so thank you for any and all help!
I think YowE3K has the right approach. I refactored his code because I don't like Do Loop.
Sub AddName()
Dim myNameBase As String
Dim arr() As String
Dim maxName As Long
Dim n As Name
myNameBase = "AddSection_" & Replace(Worksheets("Add Section").Range("D3").Value, " ", "")
For Each n In Names
If n.Name Like myNameBase & "*" Then
If n.Name = myNameBase Then
maxName = 1
ElseIf n.Name Like myNameBase & ".*." Then
arr = Split(n.Name, ".")
If arr(UBound(arr) - 1) >= maxName Then maxName = arr(UBound(arr) - 1) + 1
End If
End If
Next
Selection.Name = myNameBase & IIf(maxName, "." & maxName & ".", "")
End Sub
YowE3K Thanks for the help!
I believe what you are trying to do is:
Selection.Name = "AddSection_" & Replace(Worksheets("Add Section").Range("D3").Value, " ", "")
or, setting it up to ensure that the range name has not yet been used, perhaps something like:
Dim myName As String
Dim maxSuffix As Long
Dim n As Name
myName = "AddSection_" & Replace(Worksheets("Add Section").Range("D3").Value, " ", "")
maxSuffix = 0
For Each n In Names
If Left(n.Name, Len(myName)) = myName Then
If IsNumeric(Mid(n.Name, Len(myName) + 1)) Then
If CLng(Mid(n.Name, Len(myName) + 1)) > maxSuffix Then
maxSuffix = CLng(Mid(n.Name, Len(myName) + 1))
End If
End If
End If
Next
Selection.Name = myName & (maxSuffix + 1)
This only increments the count if the existing base name has been used before, i.e. AddSection_OilFurnace1, then AddSection_OilFurnace2, then maybe AddSection_GasFurnace1 - it doesn't go AddSection_OilFurnace1, AddSection_GasFurnace2, AddSection_OilFurnace3 - but maybe it is useful.
I have a principal sheet (Launch Tracker) that needs to be updated from a database. I have put the extraction of the database on an adjacent sheet (LAT - Master Data).
What I would like to do is that if the value of the columns H, O, Q are similar then it would replace the lines from column "E" to "AL" on the (Launch Tracker), if there is no match I would like to add the entire line at the end of the (Launch Tracker) sheet.
I already have this code that was running when I made a test, but now it doesn't seem to be working and I cannot figure out why.
Option Explicit
Option Base 1
Dim Ttrak_concat, Tdata_concat, Derlig As Integer
Sub General_update()
Dim Cptr As Integer, D_concat As Object, Ref As String, Ligne As Integer, Lig As Integer
Dim Start As Single
Dim test 'for trials
Start = Timer
Application.ScreenUpdating = False
Call concatenate("LAT - Master Data", Tdata_concat)
Call concatenate("Launch Tracker", Ttrak_concat)
'collection
Set D_concat = CreateObject("scripting.dictionary")
For Cptr = 1 To UBound(Ttrak_concat)
Ref = Ttrak_concat(Cptr, 1)
If Not D_concat.exists(Ref) Then: D_concat.Add Ref, Ttrak_concat(Cptr, 2)
Next
'comparison between the sheets
Sheets("LAT - Master Data").Activate
For Cptr = 1 To UBound(Tdata_concat)
Ref = Tdata_concat(Cptr, 1) 'chaineIPR feuil data
Ligne = Tdata_concat(Cptr, 2) 'localisation sheet data
If D_concat.exists(Ref) Then
Lig = D_concat.Item(Ref) 'localisation sheet track
Else
Lig = Derlig + 1
End If
Sheets("LAT - Master Data").Range(Cells(Ligne, "E"), Cells(Ligne, "AL")).Copy _
Sheets("Launch Tracker").Cells(Lig, "E")
Next
Sheets("Launch Tracker").Activate
Application.ScreenUpdating = False
MsgBox "mise à jour réalisée en: " & Round(Timer - Start, 2) & " secondes"
End Sub
'---------------------------------------
Sub concatenate(Feuille, Tablo)
Dim T_coli, T_colp, T_colr, Cptr As Integer
Dim test
With Sheets(Feuille)
'memorizing columns H O Q
Derlig = .Columns("H").Find(what:="*", searchdirection:=xlPrevious).Row
T_coli = Application.Transpose(.Range("H3:H" & Derlig))
T_colp = Application.Transpose(.Range("O3:O" & Derlig))
T_colr = Application.Transpose(.Range("Q3:Q" & Derlig))
'concatenate for comparison
ReDim Tablo(UBound(T_colr), 2)
For Cptr = 1 To UBound(T_colr)
Tablo(Cptr, 1) = T_coli(Cptr) & " " & T_colp(Cptr) & " " & T_colr(Cptr)
Tablo(Cptr, 2) = Cptr + 2
Next
End With
End Sub
Would someone have the solution to my problem?
Thank you in advance :)
EDIT 11:48
Actually the code runs now but It doesn't work the way I need it to. I would like to update the information on my sheet Launch tracker from the LAT - Master data sheet when the three columns H, O and Q are the same. The problem is that I have checked and some lines present in the LAT - Master Data sheet are not being added into the Launch tracker sheet after running the macro... Does someone have any idea why ?
Agathe
A type mismatch means that you gave a function a parameter that has the wrong type. In your case that means that UBound can't deal with T_colr or ReDim can'T deal with UBound(T_colr). Since Ubound always returns an integer, it must be T_colr.
If Derlig=3 then Application.Transpose(.Range("Q3:Q" & Derlig)) won't return an array but a single value (Double, String or whatever). That's when UBound throws the error.
You will also get an error with T_coli(Cptr) etc.
What you could do to prevent this is to check if Derlig = 3 and treat that case individually.
If Derlig = 3 Then
ReDim Tablo(1, 2)
Tablo(1, 1) = T_coli & " " & T_colp & " " & T_colr
Tablo(1, 2) = 3
Else
ReDim Tablo(UBound(T_colr), 2)
For Cptr = 1 To UBound(T_colr)
Tablo(Cptr, 1) = T_coli(Cptr) & " " & T_colp(Cptr) & " " & T_colr(Cptr)
Tablo(Cptr, 2) = Cptr + 2
Next Cptr
End If
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have displayed YES if the Data of Column C>=0.05 and NO if it is not satisfied . Also , I have done same with Column D in the Excel. The program Code is Given.
Now , I want to Modify my program . I want to display all the Output in single display Box like in Qbasic Programming , C programming . Also, If My output is YES , Just I need to display YES and If it is NO , I need to Display corresponding values of A cell .
The Code is Given
Sub ArrayLoops1()
Dim arrCMarks()
Dim arrDMarks()
Dim i, j As Integer
a = 0
b = 0
'For Column C
arrCMarks = Range("C2:C1439").Value
For i = LBound(arrCMarks, 1) To UBound(arrCMarks, 1)
If arrCMarks(i, 1) >= 0.005 Then
a = a + 1
End If
Next i
If a = 0 Then
MsgBox (" YES ")
Else
MsgBox ("NO")
End If
' For Column D
arrDMarks = Range("D2:D1439").Value
For j = LBound(arrDMarks, 1) To UBound(arrDMarks, 1)
If arrDMarks(j, 1) >= 0.005 Then
b = b + 1
End If
Next j
If b = 0 Then
MsgBox ("YES")
Else
MsgBox ("NO")
End If
End Sub
To make sure I understood your problem correctly:
If at least one of the values in Column C is bigger than or equal 0.005, you want to display a MsgBox saying "Yes", if no value is bigger or equal one that says "No" and the same thing again for column D?
And now you want to combine that in a single MsgBox?
In that case, do the following:
Format your code to have a better overview
We can not stop iterating anymore because we need to find all values.
Construct a String out of multiple elements
Resulting Code:
Sub ArrayLoops1()
Dim i As Integer, j As Integer
Dim a As Boolean, b As Boolean
Dim MsgString As String
MsgString = "Column C: "
'For Column C
For i = 2 To 1439
If Range("C" & i).Value >= 0.005 Then
If a = False Then
a = True
MsgString = MsgString & "NO, values from coumn A are:" & vbCrLf
End If
'Add value from column A
MsgString = MsgString & Range("A" & i).Value & vbCrLf
'Can not stop iterating since we need to find all values
End If
Next i
If a = False Then
MsgString = MsgString & "YES" & vbCrLf
End If
MsgString = MsgString & "Column D: "
' For Column D
For j = 2 To 3
If Range("D" & i).Value >= 0.005 Then
If b = False Then
b = True
MsgString = MsgString & "NO, values from coumn A are:" & vbCrLf
End If
'Add value from column A
MsgString = MsgString & Range("A" & i).Value & vbCrLf
'Can not stop iterating since we need to find all values
End If
Next j
If b = False Then
MsgString = MsgString & "YES"
End If
'Display the message
MsgBox MsgString
End Sub
BTW, the line
Dim i, j As Integer
results in i beeing a Variant (not good) and only j beeing an Integer.
Better:
Dim i as Integer, j as Integer
Bye, vat
Edit: If result is No, the corresponding value from column A is displayed (see comments below)
Edit 2: The code now does not stop iterating since we need to find all violating values. All corresponding values from column A are now shown.
Okay this will output a one msgbox:
Sub ArrayLoops1()
Dim arrCMarks()
Dim arrDMarks()
Dim i As Integer, j As Integer
Dim otptStr As String
'For Column C
arrCMarks = Range("C2:C1439").Value
For i = LBound(arrCMarks, 1) To UBound(arrCMarks, 1)
If arrCMarks(i, 1) >= 0.005 Then
otptStr = otptStr & "C: " & arrCMarks(i, 1) & " A" & i + 1 & ": " & Range("A" & i + 1).text & vbCrLf
End If
Next i
' For Column D
arrDMarks = Range("D2:D1439").Value
For j = LBound(arrDMarks, 1) To UBound(arrDMarks, 1)
If arrDMarks(j, 1) >= 0.005 Then
otptStr = otptStr & "D: " & arrDMarks(j, 1) & " A" & j + 1 & ": " & Range("A" & j + 1).text & vbCrLf
End If
Next j
MsgBox otptStr, vbOKOnly, "Both Columns"
End Sub
It will output any that are greater than the .005.
Unless you (or your users) are totally obsessed with popup dialogs, I would suggest to use a filter instead.
Such a filter would hide the majority of rows, leaving only the ones where column C or D, or both, satisfy some condition. The reason for a row to remain visible, will be reported in a separate column.
Sub FilterCD()
' Use column Z to report violating columns.
' In this example: C = the value in column C > 0.005
' D = the value in column D < 0.006
' CD = both
Range("Z2").Formula = "=CONCATENATE(IF(C2>0.005,""C"",""""), IF(D2<0.006,""D"",""""))"
Range("Z2:Z6").FillDown
' Hide rows where column Z is empty.
AutoFilterMode = False
Cells.AutoFilter Field:=26, Criteria1:="<>"
End Sub
Notes:
Adding more column in addition to C and D, is straightforward; CONCATENATE accepts any number of arguments.
You need a header row above your data to make this work. In other words, your data should start from row 2. Considering your original code, I guess that is already the case with you.
You can use Ctrl+Shift+L to undo the filter afterwards.
On big Excels sheets, I expect this code to be a lot faster than anything using For loops. But I must admit I did not profile it.
Please let me know if there is anything in my answer that does not meet your demands.
For active_row = 9 To last_row
ws1_func_loc = ThisWorkbook.Sheets(ws1).Cells(active_row, "C").Value
ws1_mat_id = ThisWorkbook.Sheets(ws1).Cells(active_row, "D").Value
ws1_mat_qty = ThisWorkbook.Sheets(ws1).Cells(active_row, "I").Value
ws1_reason2 = ""
zc_sum = WorksheetFunction.SumIfs(ThisWorkbook.Sheets(ws2).Range("F:F"), ThisWorkbook.Sheets(ws2).Range("K:K"), ws1_func_loc, ThisWorkbook.Sheets(ws2).Range("N:N"), ws1_mat_id, ThisWorkbook.Sheets(ws2).Range("S:S"), "ZC")
zk_sum = WorksheetFunction.SumIfs(ThisWorkbook.Sheets(ws2).Range("F:F"), ThisWorkbook.Sheets(ws2).Range("K:K"), ws1_func_loc, ThisWorkbook.Sheets(ws2).Range("N:N"), ws1_mat_id, ThisWorkbook.Sheets(ws2).Range("S:S"), "ZK")
'some other If conditions...
ElseIf zc_sum = 0 And zk_sum > 0 Then
row_match_count = WorksheetFunction.CountIf(ThisWorkbook.Sheets(ws2).Range("K:K"), ws1_func_loc)
Set found = ThisWorkbook.Sheets(ws2).Range("K:K").Find(What:=ws1_func_loc) 'find() found nothing on 2nd iteration
For i = 1 To row_match_count
If ThisWorkbook.Sheets(ws2).Cells(found.Row, "N").Value = ws1_mat_id And ThisWorkbook.Sheets(ws2).Cells(found.Row, "S") = "ZK" And Not found Is Nothing Then
ws1_reason2 = ws1_reason2 & Chr(10) & ThisWorkbook.Sheets(ws2).Cells(found.Row, "R").Value & ", " & "qty " & ThisWorkbook.Sheets(ws2).Cells(found.Row, "F").Value & ", " & ThisWorkbook.Sheets(ws2).Cells(found.Row, "U").Value & ", " & ThisWorkbook.Sheets(ws2).Cells(found.Row, "W").Value
Set found = Sheets(ws2).Range("K:K").FindNext(After:=found)
Else
Set found = Sheets(ws2).Range("K:K").FindNext(After:=found)
End If
Next i
ThisWorkbook.Sheets(ws1).Cells(active_row, "O").Value = ws1_reason2
ElseIf .......
I am trying to do a multi criteria search whereby I am finding all the rows in worksheet 2 (ws2) which matches the values in a specific row in worksheet 1 (ws2).
It works during the first For loop iteration, i.e. active_row = 9, but during the second iteration, i.e. when active_row = 10, Set found = ThisWorkbook.Sheets(ws2).Range("K:K").Find(What:=ws1_func_loc) returns Nothing.
But there is definitely at least a match because row_match_count comes up with a value greater than 0.
I finally figured out what's wrong.
There is a bunch of drop down list in ws2 which will filter the results.
If I used the drop down list to filter the rows, ThisWorkbook.Sheets(ws2).Range("K:K").Find(What:=ws1_func_loc) will only be able to see/find from the filtered results, while WorksheetFunction.CountIf(ThisWorkbook.Sheets(ws2).Range("K:K"), ws1_func_loc) is still able to see the whole worksheet.