Go to Top

More fun with Inner Joins

A while back I wrote about a Inner Join technique using a date range. (You can find that post here.)

Today I’m going to take it a step further and discuss using inner joins to another query and conclude with an issue in Access you may shed some light on.

SQL Server Hosting

Access can work great in large companies, call us to discuss

Using Queries as Inner Joins

For the longest I’ve been using make table queries to calculate totals and percentages, then linked the tables in secondary queries to perform updates. For example, take a look at the following tblWidgetImport table:

The table displays the total production by WidgetTypeID per week. What I needed to do was calculate the percentage of each Widget’s total for the week, and then update the PercentWeeklyWidget column.

I can calculate totals by week using the following query:

Which produces the following results:

Now that I have my summary query figured out I used it in an Inner Join query with the original table to calculate percent of each WidgetTypeID:

The query above will produced the following result set:

Nice! I now have a query that will calculate percent of each widget type by week without using a temporary table! Now I just have to insert this query with the original table to update the WeeklyWidgetPercent column, what could go wrong?

Something Went Wrong

I created the following query to update the original table using the two queries above:

When I try to execute this query Access returns “Must use an updatable query.” Ben helped me with these complex joins and says that of all RDBMS out there, Access is probably the most stingy whenever it comes to executing an update query using a summary query. As soon as a query includes a source that’s non-updatable (e.g. aggregations), the whole query is non-updatable even though we aren’t trying to update the aggregated query but a base table using values from aggregated tables. Luke Chung has a great white paper on this issue here.

In this situation, we have two choices; export the query result into temporary table as I’ve always done or wrap the query into a VBA function which Access will allow.

Where GetWeeklyPercentByType() is a VBA function that uses a DAO.OpenRecordset. It would work but since we’d be opening recordset for each row, it would be slower than just making tables and linking them.

Taking your inner join queries to the next level will require you to invest more time, but will provide you with faster results and less clutter in your database.

About Juan Soto

Juan Soto is a Senior Access Developer at IT Impact Inc. and a Microsoft Access MVP. He specializes in Access with SQL Server databases. His passion for Access has led him to helping a wide range of businesses in helping them establish a secure, stable and efficient environment with SQL Server. He's a frequent speaker at Access user groups nationwide and recently spoke at the Orange County SQL Saturday # 73. If you wish to have Juan speak at your next group meeting you can contact him here.

4 Responses to "More fun with Inner Joins"

  • Kevin Anderson
    November 21, 2011 - 7:44 pm Reply

    Regarding using a temporary table versus a VBA function workarounds, what are the advantages to using VBA? The temp tables solution makes debugging easier, but it adds housekeeping chores.

    • Juan Soto
      November 22, 2011 - 12:41 am Reply

      Hi Kevin!

      The temp table is almost always quicker since you can do a inner join and perform one query vs calling the function for each record in the table.


  • Zev Spitz
    November 15, 2011 - 1:09 am Reply

    As far as the slow recordset goes, you can create a snapshot-type recordset and store it in a module level variable. Then, you only create the recordset once. Each time the function gets called, you only have to find the appropriate record.

    • Juan Soto
      November 15, 2011 - 6:44 am Reply

      Great comment Zev, thanks!


Leave a Reply

Your email address will not be published. Required fields are marked *


Contact Us
close slider
  • This field is for validation purposes and should be left unchanged.