3 4
Subqueries are often overlooked because in most cases nested queries are more popular and easier for the SQL novice to create. Any time you base one query on another, you're dealing with a nested query, and often that's the appropriate choice. On the other hand, a nested query can be slow. You might want to try replacing a nested query with a subquery to compare performance. However, subqueries are not necessarily superior to nested queries and can actually slow things down. There's no real tried-and-true rule of thumb you can use for guidance. Being aware that you have an alternative is probably the best guideline.
The next time you're dealing with a nested query, try to rewrite it as a subquery and see whether there's any improvement in performance. Unless you're dealing with a particularly complex set of criteria or a huge amount of data, you probably won't notice much difference, but it's worth a try.
To create a subquery from a nested query, follow these steps:
Most of the time, Jet can handle the subquery. When it can't, you can try rewriting the subquery or abandon the effort.
Now let's take a look at a nested query and try rewriting it as a subquery. Suppose you want to find the oldest order in the Northwind Orders table. You also want to identify that order by customer. You can use the Min aggregate function to return the oldest order, but the minute you add the Customer field to the mix, you change the dynamics of the group, and the query returns a record for every customer with a different order date.
To solve the problem using a nested query, follow these steps:
Figure 11-25. Use the Min aggregate function to return the oldest order.
For more information about aggregates, see Chapter 9, "Using Queries to Select Data."
Figure 11-26. Base a second query on the first query.
Figure 11-27. The nested query returns the oldest order and the name of the customer who placed it.
Let's review the two SQL statements for both queries. The first (qryMax1) query's statement looks like this:
SELECT Min(Orders.OrderDate) AS MinOfOrderDate FROM Orders;
A simple SELECT statement returns the minimum value from the OrderDate field from the Orders table. The second query looks like this:
SELECT Orders.CustomerID, qryMax1.MinOfOrderDate FROM qryMax1 INNER JOIN Orders ON qryMax1.MinOfOrderDate = Orders.OrderDate;
This time there are two data sources: qryMax1 and Orders are related on the OrderDate and MinOfOrderDate fields. If the two entries match, the query will return the CustomerID and the OrderDate value for that record.
The alternative subquery looks like this:
SELECT Orders.CustomerID, Orders.OrderDate FROM Orders WHERE (((Orders.OrderDate) In (SELECT Min(Orders.OrderDate) As OrderDate FROM Orders)));
The WHERE clause replaces the JOIN. Because you're working only with the Orders table, references to qryMax1 need to be restated in terms of the Orders table, as follows:
If the transition seems complicated, don't worry. Once you've actually created a subquery from a nested query a few times, you'll get the hang of it.