0

Most people use the .Find method of a range object or use functions like If Not IsError(Application.Match([Value to Search in the Range],[Range to Search],0)) to determine whether a certain value can be found in a range. Other methods can be found in here. But if you want to match more than one criteria, it gets a little more complicated.

For instance, I want to check whether a certain Person/Date pair is present in another worksheet then write that pair if not found in the said worksheet. Referring to the example below.

enter image description here

The first way I would think of is use the code below:

Option Explicit
Sub Payroll()

Dim i As Long, j As Long, Present As Long
Dim Total_rows_HoursWorked As Long
Dim Total_rows_DailyTimeRecord As Long

ThisWorkbook.Worksheets("Hours Worked").Cells(1, 1) = "Person"
ThisWorkbook.Worksheets("Hours Worked").Cells(1, 2) = "Date"

Total_rows_DailyTimeRecord = ThisWorkbook.Worksheets("Daily Time Record").Range("A" & Rows.Count).End(xlUp).Row

For i = 2 To Total_rows_DailyTimeRecord
    Present = 0
    Total_rows_HoursWorked = ThisWorkbook.Worksheets("Hours Worked").Range("A" & Rows.Count).End(xlUp).Row
    For j = 2 To Total_rows_HoursWorked
        If ThisWorkbook.Worksheets("Daily Time Record").Cells(i, 1) = ThisWorkbook.Worksheets("Hours Worked").Cells(j, 1) And _
        ThisWorkbook.Worksheets("Daily Time Record").Cells(i, 2) = ThisWorkbook.Worksheets("Hours Worked").Cells(j, 2) Then
            Present = 1
        End If
    Next j
    If Present = 0 Then
        ThisWorkbook.Worksheets("Hours Worked").Cells(Total_rows_HoursWorked + 1, 1) = ThisWorkbook.Worksheets("Daily Time Record").Cells(i, 1)
        ThisWorkbook.Worksheets("Hours Worked").Cells(Total_rows_HoursWorked + 1, 2) = ThisWorkbook.Worksheets("Daily Time Record").Cells(i, 2)
    End If
Next i

End Sub

The output would be below:

enter image description here

But the issue with this is that it is very inefficient which will result it to run through more rows that are needed and it will be very slow especially if size of worksheets increase.

I can opt to use Arrays as well in order to speed up instead of looping through each row in a worksheet but it would still have to go through more rows than needed in order to find a match.

Another method that can be used is .Autofilter to attempt to look for matches in a certain range to minimize the looping to only those that match a certain criteria. But there is also some lag to this method but is generally faster than the first method.

What is a better way or best way of doing such tasks?

Edit: It is not just finding the unique values but also similar to finding all values that match a certain set of criteria such as the example below:

enter image description here

Charles William's blog made it in a way that the ranges are resized for Application.Match and .Find but shows that Variant Array does the best but does that mean the only option is to create a nested loop and loop through each one by one, but using an array?

Pherdindy
  • 1,168
  • 7
  • 23
  • 52
  • There's a huge difference in the algorithms that can be used if the data is ordered – Nick.Mc Jan 07 '20 at 11:05
  • Seems to me you like to keep unique values from column A & B? Rather than loop/iterate. Correct? – JvdV Jan 07 '20 at 11:27
  • 1
    In your small examples, it's going to always be quicker using code or possibly even array formulae. However, if the number of fields to match on increases and/or the number of rows increase significantly you might want to investigate using SQL within Excel. – CLR Jan 07 '20 at 11:35
  • @Nick.McDermaid Is there a reference of algorithms that you can provide? It may be nice to have an idea if there is a certain order that data should be arranged to make it more efficient – Pherdindy Jan 08 '20 at 09:01
  • @JvdV Actually the unique values is only the first step I will also have to aggregate the values from the `Daily Time Record` worksheet and perform some calculations on them so i'll also have to find all the rows in `Daily Time Record`'s column A & B that match `Hours Worked`'s column A & B as shown in the edited main post – Pherdindy Jan 08 '20 at 09:04
  • 1
    @CLR Perhaps I can take a look into SQL within Excel for database functions – Pherdindy Jan 08 '20 at 09:14
  • 1
    To query data use sql! No more coding vba and looping through ranges. You even don't need a database for start (but of course SQL Server , MySQL, Postgre, etc. are recommend (not`Ms Access`)) as you can query ranges on sheets https://learn.microsoft.com/en-us/previous-versions/tn-archive/ee692882(v=technet.10)?redirectedfrom=MSDN – ComputerVersteher Jan 08 '20 at 09:46
  • @ComputerVersteher Great read this is I suppose the best way to go. Although it was written about 10-11 years ago is the information still updated or are there some revisions to it – Pherdindy Jan 08 '20 at 10:16
  • 1
    vba hasn't change much (except upgrade to x64), so still valid. You may want to use`Microsoft.ACE.OLEDB.12.0`instead of`Microsoft.Jet.OLEDB.4.0`see [connection-Strings](https://www.connectionstrings.com/ace-oledb-12-0/). [Making repeated ADODB queries from Excel-SQL Server](https://codereview.stackexchange.com/a/143901/175456) may contain useful information (as Matthieu knows how to use [Excel,VBA](https://rubberduckvba.wordpress.com/2019/12/19/code-name-sheet1/) and SQL-Server), Try some links of the related-section. – ComputerVersteher Jan 08 '20 at 12:37
  • @ComputerVersteher Upon checking, I was informed that the first reference used `VBScript` instead of `VBA` and will not work if typed in the `VBE` but I guess I just have to find the `VBA` equivalent – Pherdindy Jan 10 '20 at 07:51
  • [Key Differences Between Visual Basic for Applications and VBScript](https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/ms970436(v=msdn.10)?redirectedfrom=MSDN#system-objects), Visual Basic for Applications [Features not in VBScript](http://www.csidata.com/custserv/onlinehelp/vbsdocs/vbs231.htm), VBScript [Features not in Visual Basic for Applications](http://www.csidata.com/custserv/onlinehelp/vbsdocs/vbs236.htm). Usually you can mix docs and code, with only minor changes. – ComputerVersteher Jan 15 '20 at 06:05

1 Answers1

-1

It does somewhat depend on the data. Ignoring the possibilities of sorting and using a hi-lo binary search then there is a comparison of using FIND vs MATCH vs variant array for a 2-column search here on my blog.

https://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/

Charles Williams
  • 23,121
  • 5
  • 38
  • 38
  • Is it fine in the long run to use a `Variant array` for my application without the need for any sorting/arrangements or are there common sorting methods that should be a standard procedure to go with using an array? – Pherdindy Jan 08 '20 at 09:38
  • Variant array is usually fast enough and easy enough for most cases. – Charles Williams Jan 09 '20 at 18:02
  • Thanks i'm just worried it will start taking up a long time to calculate once it reaches rows in the hundreds of thousands as i've had some applications that took a long time to finish and is annoying for the users – Pherdindy Jan 10 '20 at 08:09
  • probably take about half a second for a million rows, depending on PC speed and the number of pairs to find. If thats not fast enough then you would need a different algorithm – Charles Williams Jan 10 '20 at 19:58