![]() |
Microsoft Access Query Tips and Techniques (SQL and VBA)by Luke Chung, President of FMS, Inc.Revised with examples from Microsoft Access 2007 and 2010. Also applies to Microsoft Access 2003 and earlier. OverviewMicrosoft Access is the most popular Windows database program. A major reason for its success is its revolutionary query interface. Once data is collected in a database, analysis and updates need to be performed. Queries offer the ability to retrieve and filter data, calculate summaries (totals), and update, move and delete records in bulk. Mastering Microsoft Access queries will improve your ability to manage and understand your data and simplify application development. Queries Hide the Complexity of Microsoft Access SQL SyntaxThe visual representation of tables and the graphical links between them makes Microsoft Access queries extremely easy to use and hides the complexity of writing the raw Microsoft Access SQL. Fortunately, the nice user interface still allows very powerful and advanced analysis. The entire query engine is modeled on SQL systems and can switch between the graphical query design and SQL syntax. Many Microsoft Access users and developers learned SQL from this feature. Knowing the many features of Microsoft Access queries allows you to perform advanced analysis quickly without programming. This presentation covers the basics of queries revealing a variety of subtleties. It quickly moves to more advanced topics with hints and techniques for creating sophisticated queries. Finally, programmatic use of queries is presented:
Download Sample Access Databases (162K) Query TypesMicrosoft Access supports many types of queries. Here is a description of the major categories:
Select queries are the most common queries and can be used for viewing and a data source for forms, reports, controls, and other queries. The other queries create or change data and are known collectively as Action queries. Basic Select QueriesThe most basic Select queries retrieve the records you specify from a table. You can choose the fields from a table to display, and specify the criteria for selecting records. In the most cases, while viewing the query results you can modify the data and update the original records. These updateable views are extremely powerful. Selecting Table and FieldsThe first step in creating a query is to specify the table or tables to use and the fields to display. Selecting tables is simple. Just choose the table from the list when the query is first created or use the Add Table command from the Query menu. The selected table is placed on the upper portion of the query design window. From there you can select the fields for the query by double clicking on them or selecting several fields (using Shift-Click or Ctrl-Click) and dragging them to the bottom portion: the query by example (QBE) grid. Make sure the Show option is checked to display the field. Sorting and Reordering FieldsOnce the fields are placed on the QBE grid, you can reorder the fields by clicking on the column and dragging it to the place you want. To sort the results, specify the Sort option under the fields to sort. You can choose Ascending or Descending order. Note that you can turn off the Show setting and sort on a field that does not appear in the display. Renaming FieldsA very nice feature of Microsoft Access queries is the ability to rename fields. You may have your data stored in field names that are not easily understood by users. By using a query expression, you can change the field name the user sees. For instance, a field named "CustID" could be changed to "Customer ID" by placing the new name followed by a colon and the original name in the QBE field cell: Customer ID:[CustID]. Using Calculated Fields (Expressions)In addition to retrieving fields from a table, a Select query can also display calculations (expressions). Of course, expressions cannot be updated since they do not exist in the original table. Expressions are extremely powerful and allow you to easily display complex calculations. There is an Expression Builder that simplifies the selection of fields and functions. By default, expression fields are named "Expr1", "Expr2", etc.; therefore, you usually want to rename them to something more understandable. Setting Query PropertiesWhile designing a query, you can choose View | Properties or right click on the top portion of the query and choose Properties to see and modify the query properties.
DescriptionThis property lets you provide a description for the query to help you remember its purpose. Default ViewShow the results in a datasheet like a table, or a pivot chart or pivot table. Output All FieldsThis option is usually set to No. If it is changed to Yes, all the fields of all the tables in the query are shown. In general, you should leave this property alone and specify the fields desired in the QBE grid. Top ValuesRather than retrieving all records, you can specify the top n records or n percent, where n is the value specified here. Unique ValuesBy default this is set to No and all records are retrieved. If this is changed to Yes, every record retrieved contains unique values (SQL uses the SELECT DISTINCT command). That is, no retrieved records are identical. For instance, you can run a query for the State field of the Patient table. With this set to No, the result is a record for each patient. When set to Yes, only the list of unique states is displayed. When set to Yes, the query is not updateable. Unique RecordsBy default this is set to No and all records are retrieved. For one table queries, this property is ignored. For multi-table queries, if it is set to Yes, (similar to using a DISTINCTROW in a SQL statement) only unique records in the underlying tables are retrieved. The Unique Records and Unique Values properties are linked and only one can be set to Yes (both can be No). When Unique Records is Yes, Unique Values is automatically set to No. When both properties are set to No, all records are returned.
Non-Updateable QueriesSome queries are not updateable. For more information, read our paper addressing the warning message you see: This Recordset is not updateable: Dealing with non-updateable queries in Microsoft Access SQL Server PropertiesThere are several properties related to SQL Server tables and are more technical and rarely need to be modified. For more information refer to Microsoft Access' on-line help system. Filter, Order By, Filter On Load, Order By On LoadLike a form, you can specify the Filter and Order By settings for a query. However, this is usually part of the query's SQL statement. By using the Filter and Order By properties, you have the extra advantage of specifying the Filter On Load and Order By On Load properties to apply them or not. Subdatasheet Name, Link Fields, and SizeIf you want to display a subdatasheet to show a one-to-many relationship between the results in this query with data from another table, you can specify them here. There is a significant performance cost for having subdatasheets, so only add them if you want them. Setting Field PropertiesIn addition to query properties, each field also has properties that can be set. Move to a field in the QBE grid and right click. Depending on the field type, different properties are available. The most important properties are for numeric and date fields. You can specify how the fields are formatted when the query is run. Viewing Results and SQL EquivalentOnce the query is completed, you can view its results by switching from Design to DataSheet view. You can also view the SQL equivalent. You can even edit the SQL syntax directly and view the results and/or switch to Design view. Setting CriteriaThe bottom section of the QBE grid is several rows for Criteria. These are optional entries to specify which records are retrieved. If you want all the Patients from the state of Virginia, just enter "VA" in the State's criteria. To further narrow the scope, you can enter criteria for several fields. Multi-Field Query CriteriaEntering criteria on the same row for several fields performs an AND query between the fields. That is, records that match the criteria in field 1 AND the criteria in field 2, etc. are retrieved. If criteria is placed in different rows, an OR query is performed: retrieve all records matching criteria in field 1 OR criteria in field 2, etc. Criteria TypesThe simplest criteria is the exact match. Just enter the value desired in the field's criteria section. Remember that by using the Show option to eliminate the field from the display, you can specify criteria in fields the user never sees. <>, <, >, Between .. And ..You can also retrieve records where a field does not have a particular value by using "< >" followed by the value you don't want. Similarly, you can use >, <, >=, or <= for ranges. To select records with values between two values, use the BETWEEN .. AND .. syntax. NullsTo select records with Null values, enter Is Null. The opposite is Is Not Null. For text fields, remember that zero length strings ("") are not nulls. OR and IN(.., .., ..)To select records where a field can have one of several values, use the OR command. You can simply say: "MD" or "DC" or "VA". Alternatively, the IN command performs the same function: IN("MD", "DC", "VA"). The second syntax is easier if you have many values. Of course, if you have a very large number of values, it is better to keep those values in a table and link your query to it. That is easier to maintain than OR or IN clauses inside queries. Wildcard SearchesSometimes, you need to search for a particular letter or digit. Combined with the Like command, wildcards let you specify such criteria. These are the wildcard characters Microsoft Access uses:
For instance, if you are interested in a text field where the second letter is "a", the criteria would be: Like "?a*". If you were seeking values where the second letter could be an "a" or "e", the criteria would be: Like "?[ae]*". The opposite of this (all values that do not have "a" or "e" as the second letter) is performed by adding an "!": Like "?[!ae]*". Finally, to select a range of letters (say "a" through "e"), add a dash between the letters: Like "?[a-e]*". To search for a wildcard character, enclose the value in brackets. For instance, to find values that end in a question mark, use this: Like "*[?]" Advanced Select Queries
Using ParametersOften it is not possible to know in advance the criteria for a query field. In such cases, where the filter values are not known until runtime, a variable (parameter) can be used. When these queries are run, the user is prompted for the value of each parameter. (The parameters can also be assigned programmatically). Using parameters in queries is extremely powerful and converts static "hard-coded" queries to flexible, dynamic ones. The use of parameters can significantly reduce the number of queries you need, makes queries more useful, and simplifies database maintenance. Parameters can be added very easily. Rather than entering the value of a criteria, enter between brackets the prompt you want the user to see when the query is run. The value the user enters replaces the parameter in the query. In the following example, a parameter [Enter State Name:] is the criteria in the [State] field, and [Enter Minimum Age:] is the parameter in the [Age] field. When this query is run, the user is prompted for the state desired and minimum age, and the records matching that value are retrieved.
Parameters work provided the parameter definition does not conflict with the field name among the query's tables. To better define a parameter, you should specify it in the list of parameters. This is an optional step, but there are good reasons to do so. Right mouse click on the top part of the query and choose Parameters. This form appears to let you list each parameter name and its type:
By explicitly defining parameters, users are forced to enter values conforming to the type. While it may not matter for text fields, it is useful for numeric and date fields. This minimizes data entry errors that cause a "Can't evaluate expression" error message to appear. Using Access FunctionsOne of the most powerful features of Microsoft Access queries is their support for Access functions. This is most useful in Update queries, but can also be used in Select queries. The Advanced: Access Functions query is an example of this feature:
This query selects the Country names in descending order of name length. The second field renames itself to [Length], uses the LEN function to calculate the length of each country name, sorts the length in descending order, and excludes any records with 10 letters or fewer. While this may not seem particularly useful, there are many situations where using Access functions is extremely useful and eliminates the need to program. The string functions in particular (Left$, Right$, Trim$, Mid$, UCase$, LCase$ etc.) are useful for manipulating portions of strings and changing case. Using Custom FunctionsIn addition to using Microsoft Access functions, queries also support user defined functions. Functions defined in VBA modules must return an appropriate value and can be used to manipulate each record. You can reference field values by passing the field name in brackets. Here is an example where a function (StripLead) is used to remove the leading word of a phrase if it starts with "The", "An", or "A". This is useful for sorting phrases such as book titles on "real" words:
This is the code for the StripLead function. It is passed a string and returns the string without the leading word (if any):
And this is the result. Notice how the sorting of the [Adjusted] field differs from the [Original] field:
Other Types of Select Queries
Top Records (number and percent)Select queries retrieve all the records that meet your criteria. There are occasions where you only want a subset: the top or bottom number of records. Similarly, you may just want the top or bottom percent of records. This is easy to do. Just change the query's Top Values property (right mouse click on the top portion of the query), you can specify the number of records to display. The example below (query: Other: Top 10 Auto Companies) has this set to 10:
Notice the query is retrieving records in Descending order so the Top Values option retrieves the largest values. It simply runs the query and displays the specified number of records in the query output's order. To display the lowest values, the query should retrieve records in Ascending order. Top Percent of RecordsSometimes, you want a percentage of records and not a fixed number. To retrieve the top n% of the query records, enter a percentage (e.g. 10%) rather than just a value in the Top Value option. Similarly but sorting in the opposite direction, you get the bottom percentage of records.
|
||||||||||||||||||||||||
|
These queries are similar to creating Select queries: Make Table QueriesMake Table queries are identical to Select queries except rather than creating a datasheet display of the results, a new table is created containing the results. These are particularly useful for creating temporary tables. For instance, if you are generating a series of reports while other people are changing the data, a Make Table query can create a snapshot of your data and allow your reports to work off that table. This lets you create a consistent set of reports. |
|
Append QueriesAn Append Query is similar to a Select query, but the results are inserted as new records into another table. The field names do not need to match and expressions can also be used. The other table may or may not be empty before records are inserted. |
|
Update QueriesAn Update Query in Microsoft Access allows you to modify the data in your records. This is often used to update a field with an expression or data from another table. |
|
Delete QueriesA Delete Query in Microsoft Access lets you specify the records to remove from a table. You can empty the entire table, remove records based on criteria in its fields or values in other tables. |
|
Queries can be used in forms and reports in a variety of ways. The most common is the Record Source of the form or report. Another useful place is the RowSource of a ComboBox.
Running a query with a macro is very simple. Just use the OpenQuery command and specify the query name to run. If the query has parameters, the user is prompted for the values.
If you are running an Action query, you can do the same thing; however, Action queries usually display warning messages prior to changing data. To eliminate such messages, use the SetWarnings command to turn this off and on before and after the query.
There are many ways to run queries through modules. Here are a few examples:
RecordSets let you programmatically move through a table or query. By assigning a Select query to a RecordSet, you can move through the table. Commands such as MoveNext, MoveFirst, MoveLast, MovePrevious, let you control where you are in the query. By checking the EOF status, you can make sure you stop at the end of the table. Field values are referenced with a ! then field name.
Public Sub BrowseQuery_DAO()
' Comments: Browse a query and display its fields in the Immediate Window using DAO
Const cstrQueryName = "Basics: Top 10 Most Profitable Companies"
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
' Open pointer to current database
Set dbs = CurrentDb
' Open recordset on saved query
Set rst = dbs.OpenRecordset(cstrQueryName)
' Display data from one record and move to the next record until finished
Do While Not rst.EOF
Debug.Print "Company: " & rst![Company] & " Sales: " & rst![Sales] & " Sales: " & rst![Profits]
rst.MoveNext
Loop
rst.Close
dbs.Close
End Sub
This example prints the company name and sales in the Immediate Window.
Earlier we showed how to use parameters in queries. If you want to run from code a query which has parameters you need to specify the parameters in your code. Otherwise, the user is prompted for the parameter value when the query is executed.
To pass a parameter value to a query, you need to create a QueryDef and reference its parameters collection. From there you can specify each of the query's parameters. When you are finished, you can create a recordset from it (if it is a Select query) or execute it if it is an Action query. To learn more about QueryDefs and the parameters collection, refer to the on-line help section under QueryDefs.
Public Sub RunParameterQuery_DAO(pstrState As String)
' Comments: Runs a query containing parameters
' Params : pstrState Name of state to select records
Const cstrQueryName As String = "Basics: Parameters"
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Set dbs = CurrentDb()
Set qdf = dbs.QueryDefs(cstrQueryName)
qdf.Parameters("State Abbreviation") = pstrState
' Open recordset on the query
Set rst = qdf.OpenRecordset()
Do While Not rst.EOF
Debug.Print ("ID: " & rst![ID] & " State: " & rst![State])
rst.MoveNext
Loop
rst.Close
qdf.Close
dbs.Close
End Sub
Often it is not possible to know a query's specifications in advance. In these situations, the query needs to be programmatically created. This is done be creating a SQL string containing the query to run. The example below shows a simple case, but one can easily create a more complex example where the query string (strSQL) is based on other situations (field values, user selections, etc.).
Public Sub RecordsetFromSQL_DAO()
' Comments: Browse the results of a SQL string and display it in the Immediate Window
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT Left([Company],1) AS Letter, Count(Company) AS [Count], " & _
"Avg(Sales) AS AvgOfSales, Avg(Profits) AS AvgOfProfits " & _
"FROM Fortune100 " & _
"GROUP BY Left([Company],1)"
' Open pointer to current database
Set dbs = CurrentDb()
' Create recordset based on SQL
Set rst = dbs.OpenRecordset(strSQL)
Do While Not rst.EOF
Debug.Print "Company Letter: " & rst![Letter] & _
" Sales: " & rst![AvgOfSales] & _
" Profits: " & rst![AvgOfProfits]
rst.MoveNext
Loop
rst.Close
dbs.Close
End Sub
Running your own query string is identical to the previous examples. Just base a RecordSet on the query string.
To run a saved Action query like an Update Query, use the query Execute command. The simple procedure below lets you easily run a saved query. Just pass the name of the query and it is performed:
Public Sub RunActionQuery_DAO(pstrQueryName As String) ' Comments: Sample code of running a stored (action) query ' Params : pstrQueryName Name of the query to run DoCmd.SetWarnings False CurrentDb.Execute pstrQueryName DoCmd.SetWarnings True End Sub
This procedure sets up a database variable referencing the current database, and creates a QueryDef based on the query name. The Warning message is temporarily turned off before executing the query and reset afterwards. DoEvents and DBEngine.Idle commands are used to make sure the Jet Engine has completed its tasks and releases its locks.
A MakeTable query is an Action query and can be run with the Action Query example shown earlier. The only wrinkle here is to make sure the new table is deleted prior to the Make Table query's execution. Also, the example below shows another way to execute a query without using a QueryDef.
Public Sub MakeTableFromSQL_DAO()
' Comments: Sample code running an action query created in a SQL string
' Includes simple error trapping to handle problems creating table
Const cstrNewTableName As String = "Fortune100 LetterSummary"
Dim strSQL As String
Dim strError As String
' SQL string to create a new table
strSQL = "SELECT Left([Company],1) AS Letter, Count(Company) AS [Count], " & _
"Avg(Sales) AS AvgOfSales, Avg(Profits) AS AvgOfProfits " & _
"INTO [" & cstrNewTableName & "] " & _
"FROM Fortune100 " & _
"GROUP BY Left([Company],1)"
' Delete table if it exists
On Error Resume Next
DoCmd.DeleteObject acTable, cstrNewTableName
Err.Clear
' Execute (run) the query
CurrentDb.Execute strSQL
If Err.Number <> 0 Then
strError = Err.Description
End If
On Error GoTo 0
If strError = "" Then
MsgBox "Table: [" & cstrNewTableName & "] created"
DoCmd.OpenTable cstrNewTableName
Else
MsgBox "Error creating table: " & strError
End If
End Sub
Additional code is provided in the sample database with this paper.
FMS offers a variety of other resources to help you maximize the value of your Microsoft Access data:
Document and Improve Queries with Total Access AnalyzerTotal Access Analyzer documents your entire database to provide detailed information on each object, where it's used, and recommendations to fix or improve them. Part of the analysis includes Queries. Here are some examples of the results:
More information on Total Access Analyzer |
|
|
|
|
Advanced Numerical Analysis with Total Access StatisticsIf you want to extend the power of Access queries with more advanced numerical analysis, learn more about our Total Access Statistics program. It is the leading Microsoft Access statistical analysis program. It analyzes your Access table, linked table, or query in an MDB, ACCDB or ADP, and puts its results in tables. Generate percentiles, frequency distributions, regressions, correlations, rankings, data normalization, advanced crosstabs, t-Tests, ANOVA, non-parametrics, probabilities, etc. Interactive Wizard and VBA programmatic interfaces are included with a runtime distribution library. Adding advanced numerical analysis couldn't be easier! Get more information including a free trial version. |
![]() |
|
|
|
Recordset and SQL Builders in Total Visual CodeToolsIf you want to simplify the creation and maintenance of Access/VBA code, learn about our Total Visual CodeTools program. It helps VB6/VBA developers create new code, clean up existing code, and deliver more robust solutions. Two of its builders related to queries are:
Get more information including a free 30 day trial version. |
![]() |
|
|
|
Database Maintenance and Macro Scheduler with Total Visual AgentAs you add more data to your database, you need to make sure to compact it regularly for optimal results and make backups. Additionally, you may have a series of tasks that need to be run repeatedly. For instance a set of queries, data downloads, exports, or printing a batch of reports. You can automate these tasks with a macro or some code. To launch this on a regular schedule, use our Total Visual Agent product. Total Visual Agent is a Microsoft Access scheduler to run macros, compact, and other database chores on an hourly, daily, weekly, monthly, or one time event. Easily manage an unlimited number of databases across your network. Get a free trial version. |
![]() |
Here are some other FMS papers related to data that you may find helpful:
FMS also offers custom software development services. If you're in over your head or just don't have time, contact our team. We can help you maintain, enhance, and/or migrate your Microsoft Access applications. Here's more on our Microsoft Access Consulting Services.
Good luck!
Copyright © 1998-2010, FMS Inc. All rights reserved. You may link to this page, but this information may not be republished, reprinted or retransmitted in any form without the express written permission of FMS Inc. The information provided in this document is provided "as is" without warranty of any kind.
|
For data analysis beyond the power of Microsoft Access queries:
Database documentation and analysis including object cross-reference, performance optimization, and finding unused queries:
Well written and tested modules and classes that you can use royalty-free:
Tools to standardize and enhance your module code, including an ADO and DAO Recordset Builder:
Send personalized emails with your Access data and reports:
![]() |
Contact Us
l Web questions: Webmaster
l Copyright
© 2010 FMS, Inc., Vienna, Virginia |