How to Filter an Existing Recordset

Sieve

Today, I thought I’d touch upon how you can filter an existing recordset.

I didn’t know how to approach this subject myself back in 2013 and Dirk Goldgar and Henry Habermacher were kind enough to teach me.

Recently, I saw a question on UtterAccess pertaining to this and thought it was a worthwhile subject to post on my blog to help other developers with.

The Concept

So what am I talking about exactly?

Perhaps you have a form of contacts listed that the user has already filtered down and you can easily grab that recordset from the form, but you wanted to only get the contacts from a specific city, or gender, or …

Yes, you could identify the existing filters, and new filters and create a new SQL statement to pull the info from, but you can also simply filter the form’s recordset directly.

Below are 2 variations of the same basic technique which illustrate how this can be done.

In the examples below I’m filtering only those which records are Active (Active = True), but the filter could be anything you’d like.

Method 1

    Dim rs                    As DAO.Recordset
    Dim rsFiltered            As DAO.Recordset

    Set rs = Me.RecordsetClone
    rs.Filter = "[Active] = True"
    Set rsFiltered = rs.OpenRecordset
    With rsFiltered
        If .RecordCount <> 0 Then
            .MoveFirst
            Do While Not .EOF
                ' Do something with each filtered record
                .MoveNext
            Loop
        End If
    End With

    On Error Resume Next
    If Not rsFiltered Is Nothing Then
        rsFiltered.Close
        Set rsFiltered = Nothing
    End If
    If Not rs Is Nothing Then Set rs = Nothing

Method 2

    Dim rsFiltered            As DAO.Recordset

    With Me.Recordset
        .Filter = "[Active] = True"
        Set rsFiltered = .OpenRecordset
    End With

    With rsFiltered
        If .RecordCount <> 0 Then
            .MoveFirst
            Do Until .EOF
                ' Do something with each filtered record
                .MoveNext
            Loop
        End If
    End With

On Error Resume Next
    If Not rsFiltered Is Nothing Then
        rsFiltered.Close
        Set rsFiltered = Nothing
    End If

As you can see, it truly isn’t hard, once you are aware of the basic principle and then it’s like working with any other recordset and looping mechanism.

A Few Resources on the Subject

3 responses on “How to Filter an Existing Recordset

  1. Mark Burns

    The ADO library has a related option, but the last time I tried it, there was a hidden gotcha waiting.

    The ADODB.Recordset object also has a .Filter property.
    Only, when set to a VALID SQL filter phrase (think: where clause syntax), it takes instant effect on the CURRENT recordset.
    See the ADO docs for details: https://docs.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/filter-property-ado

    Back in the day when I used this last, there were “gotcha”s with this PROPERTY though.
    If the .filter SQL expression was invalid (or even just too long – for which “too long” was left undefined), IT FAILED COMPLETELY SILENTLY. (NOT Good!)

    Whether this has changed in recent years or not, I don’t know, as I’ve never had need to try it again, preferring the requery approach (which can not fail silently).

    However, if your syntax is known-good and fairly brief, this is a worthwhile alternative also.

  2. Chris Sweetnam

    Note that the records can only be counted in DAO recordsets if the last record has been accessed.
    Instead of:
    If .RecordCount 0 Then
    .MoveFirst

    (.RecordCount will give a false value until .MoveLast has occurred)

    If NOT .EOF then
    .MoveFirst
    ‘ do stuff here

    1. Daniel Pineault Post author

      While true in the strictest sense, for the purposes of the code shown above, using .RecordCount <> 0 is perfectly acceptable to ensure that there are records. I’m not trying to get an accurate count, just insuring there are records. I’ve been using this approach for at least 15 years and it works perfectly.