$Account.OrganizationName
The Access Wizard Newsletter Tips, Tricks, and Traps for Access Users and Developers
May 2012

The Need for Speed, Part Four: Speed Up Slow Forms by Eliminating Combo Boxes with Thousands of Records

Abraham Lincoln once said, "If I had five hours to chop down a tree, I'd spend the first four sharpening my ax."

Old Abe certainly understood the importance of spending the time up front to minimize the effort and time needed to efficiently reach a goal.

This month, we'll continue our series of speeding up an application by tackling another vexing problem that invisibly slows down forms: combo boxes that contain thousands of records.

In this Issue
  • Shameless Self-Promotion Department
  • The Problem
  • The Solution: A Filter Box with a Bit of Code
  • Pulling Apart the Code
  • Final Steps and Conclusion
  • Trap of the Month: Beware of Apostrophes in Combo Boxes and in Code

  • The Problem

    Let's say that you are building a form that is designed to track orders from customers. Further, let's suppose that your business has 5,000 customers.

    Typically when you build a form, your goal is to make life as easy and efficient as possible. If your form is designed to show details about a customer, then you might be tempted to have a combo box that lists all the customers so that the user just starts typing the customer name and once found, the form populates with information about the customer.

    This approach actually works; unfortunately it's a slow process. There are a couple of problems, neither of which is immediately apparent. The first is that if the form is tied into underlying records about each customer, then the form has to load all of those records before being able to react to the user. This is a separate problem that we will cover in a future Wizard.

    A more subtle problem is associated with the combo box. Most likely, the combo box is attached to a query (or SQL statement) that returns every customer in the database. With this approach, you just start typing and, once you see the customer name, you click on it or just hit return if the typing arrives there by itself. The problem is that the combo box has to retrieve 5000 records before the form is ready for the user to do anything.


    The Solution: A Filter Box with a Bit of Code

    A much better approach is to use a bit of code that limits the combo box to just a handful of records.

    This can be accomplished by the addition of one text box and just a bit of code. Let's say that your original query behind the combo box is "Select CustomerKey, CustomerName from tblCustomer ORDER BY CustomerName".

    The text box should be labeled something on the order of "Please enter the first few letters of the customer's name." Then have an after-update event for the text box (I'll call it "txtFindCustomer". The code you'll want is as follows:

    Private Sub txtFind_AfterUpdate()
        Dim strFind As String
        strFind = Nz(Me.txtFind, "")
        If Len(strFind) = 0 Then Exit Sub
        Me.cboCustomer.RowSource = "Select CustomerKey, CustomerName from " & _
        " tblCustomer where CustomerName like '" & strFind & "*' " & _
        " order by CustomerName"
        Me.cboCustomer.SetFocus
        Me.cboCustomer.Dropdown
    End Sub


    Pulling Apart the Code

    Let's take the code line by line.

        Dim strFind As String

    This line sets up a variable to hold onto the text that the user puts into our find box.

        strFind = Nz(Me.txtFind, "")

    This line loads the user entry into our variable. Note that it has two features. First it is using the Nz function. This function handles the case when there is nothing there. Since we have said that our variable is a string, if the user has wiped out the previous entry and hit return, the search box will contain a null value. The Nz function will replace that value with the string "" (essentially a string with nothing in it). You could also accomplish exactly the same thing with:

        strFind = strFind & ""

    It's strictly a matter of style.

        If Len(strFind) = 0 Then Exit Sub

    This line essentially says that if the length of the string to find = 0, essentially "", then exit the routine. Since the user has entered a blank, we don't want to continue.

        strFind = Replace(strFind, "'", "''")

    This solves a tricky and complicated problem of apostrophes in text manipulation. See this month's trap for a full explanation of why this is necessary.

    The next line is where all the action takes place.

        Me.cboCustomer.RowSource = "Select CustomerKey, CustomerName from " & _
        " tblCustomer where CustomerName like '" & strFind & "*'" & _

    " order by CustomerName"

    The customer combo box has a row source, in our case it was a SQL statement. What we are doing here is replacing whatever is there with a new SQL statement. The beginning and ending are the same as the original:

    CustomerKey, CustomerName from
    And
    order by CustomerName

    It's the middle part, the where clause, which is the bit of magic:

    where CustomerName like '" & strFind & "*'"

    What we've done is taken the input from our user and put into our SQL statement. The word like is used with the asterisk to create a wild card search.

    If our user had entered Mc into our search box it would bring back all records starting with "Mc".

    The last two lines work in tandem:

        Me.cboCustomer.SetFocus
        Me.cboCustomer.Dropdown

    The set focus is necessary in order to do our dropdown. The dropdown statement opens up the dropdown box to show a number of records that meet the criteria (typically 8, unless you've changed it). The beauty of doing it this way is that the user gets immediate feedback and figures out how things work with very little effort or training.


    Final Steps and Conclusion

    Once you are satisfied that the find box and combo box are working the way you want them to, the next step is to remove any existing SQL statement in the Combo Box. The purpose here is to speed up form loading. Rather than retrieving 5000 records from the customer table when the form opens, it returns 0 records. It will only return records when the user has indicated what they are looking for.

    Using this approach, a filter for a combo box, rather than a combo box containing all records has two major benefits:

    1. Your form will load faster.
    2. Your user will have a much easier time finding one of a few records rather than one of 5,000.

    As a final benefit, your user is not limited by how many characters they enter into the search box. This way, they can refine their search so that they get what they want with reduced effort on their side. Wins all around!


    Trap of the Month: Beware of Apostrophes in Combo Boxes and in Code

    When manipulating text, as we did in this month's Wizard, you have to be aware of the dreaded apostrophe trap. This comes up frequently when you go after names like O'Leary, O'Malley, or O'Generic Irish name.

    The problem is that when VBA is manipulating text that is enclosed in double quotes, as soon as it hits an apostrophe, it interprets the single quote as if it were a double quote and terminates the string. When your VBA gets to the terminating double quote, it doesn't know what to do and throws up an "I'm unhappy" error message.

    The way to resolve this problem is to just double any apostrophes. You do that with a simple replace statement. For instance, this month we were manipulating a variable called strFind, and we had a line of code:

    strFind = Replace(strFind, "'", "''")

    With this statement, the code engine will turn any existing single quotes within our variable, strFind, into a single quote within the manipulated string and things will work the way they should.

    As a general rule, it is always a good idea to test any combo box or search box with a name or phrase that contains an apostrophe to make sure it can handle things gracefully.


    Shameless Self-Promotion Department

    On Wednesday evening, June 13, 2012, I will be giving a presentation to the Connecticut Access User Group - CTAUG. My talk will focus on how to store, manipulate, and manage complicated SQL statements within Access.

    If you are a developer, this session will show you how to convert SQL code managed in VBA to the familiar Access Query by Design environment.

    I'll also demonstrate how to create a complicated series of SQL steps in an easy fashion, and then adjust and debug with ease.

    Watch the CTAUG site for more information as the date approaches.

    Quick Links...

    Custom Software Home

    Access Wizard Archives

    Our Services



    Join our mailing list!


    Custom Software | Copyright Custom Software All Rights Reserved | Westford | MA | 01886