Sometimes you might want to list the records from one table or query with those from one or more other tables to form one set of records - a list with all the records from the two or more tables. This is the purpose of a union query in Access.
To effectively understand union queries, you should first be familiar with designing basic select queries in Access. To learn more about designing select queries, see Create a simple select query.
Note: The content in this article is intended for use with Access desktop databases. You can't create or use a union query in Access web databases or Access web apps.
Study a working union query example
If you've never created a union query before, you might find it useful to first study a working example in the Northwind Access template. You can search for the Northwind sample template on the getting started page of Access by clicking File > New or you can directly download a copy from this location: Northwind sample template.
After Access opens the Northwind database, dismiss the login dialog form that first appears and then expand the Navigation Pane. Click the top of the Navigation Pane and then select Object Type to organize all the database objects by their type. Next, expand the Queries group and you'll see a query called Product Transactions.
Union queries are easy to differentiate from other query objects because they have a special icon that resembles two intertwined circles representing a united set from two sets:
Unlike normal select and action queries, tables are not related in a union query, which means the Access graphic query designer can't be used to build or edit union queries. You'll experience this if you open a union query from the Navigation Pane; Access opens it and display the results in datasheet view. Under the Views command on the Home tab, you'll notice that Design View is not available when you work with union queries. You can only switch between Datasheet View and SQL View when working with union queries.
To continue your study of this union query example, click Home > Views > SQL View to view the SQL syntax that defines it. In this illustration, we've added some extra spacing in the SQL so you can easily see the various parts that make up a union query.
Let's study the SQL syntax of this union query from the Northwind database in detail:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], [Quantity] FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] FROM [Product Purchases] ORDER BY [Order Date] DESC;
The first and the third parts of this SQL statement are essentially two select queries. These queries retrieve two different sets of records; one from the Product Orders table and one from the Product Purchases table.
The second part of this SQL statement is the UNION keyword which tells Access that this query will combine these two sets of records.
The last part of this SQL statement determines the ordering of the combined records by using an ORDER BY statement. In this example, Access will order all of the records by the Order Date field in descending order.
Note: Union queries are always read-only in Access; you can't change any values in datasheet view.
Create a union query by creating and combining select queries
Even though you can create a union query by directly writing the SQL syntax in the SQL view, you might find it easier to build it in parts with select queries. You can then copy and paste the SQL parts into a combined union query.
If you'd like to skip reading the steps and instead watch an example, see the next section, Watch an example of building a union query.
-
On the Create tab, in the Queries group, click Query Design.
-
In the Show Table dialog box, double-click the table that has the fields that you want to include. The table is added to the query design window.
-
Close the Show Table dialog box.
-
In the query design window, double-click each of the fields that you want to include. As you select fields, make sure that you add the same number of fields, in the same order, that you add to the other select queries. Pay careful attention to the data types of the fields, and make sure that they have compatible data types with fields in the same position in the other queries that you are combining. For example, if your first select query has five fields, the first of which contains date/time data, make sure that each of the other select queries that you are combining also has five fields, the first of which contains date/time data, and so on.
-
Optionally, add criteria to your fields by typing the appropriate expressions in the Criteria row of the field grid.
-
After you have finished adding fields and field criteria, you should run the select query and review its output. On the Design tab, in the Results group, click Run.
-
Switch the query to Design view.
-
Save the select query, and leave it open.
-
Repeat this procedure for each of the select queries that you want to combine.
Now that you created your select queries, it's time to combine them. In this step, you create the union query by copying and pasting the SQL statements.
-
On the Create tab, in the Queries group, click Query Design.
-
Close the Show Table dialog box.
-
On the Design tab, in the Query group, click Union. Access hides the query design window, and shows the SQL view object tab. At this point, the SQL view object tab is empty.
-
Click the tab for the first select query that you want to combine in the union query.
-
On the Home tab, click View > SQL View.
-
Copy the SQL statement for the select query. Click the tab for the union query that you started to create earlier.
-
Paste the SQL statement for the select query into the SQL view object tab of the union query.
-
Delete the semicolon (;) at the end of the select query SQL statement.
-
Press Enter to move the cursor down one line, and then type UNION on the new line.
-
Click the tab for the next select query that you want to combine in the union query.
-
Repeat steps 5 through 10 until you have copied and pasted all of the SQL statements for the select queries into the SQL view window of the union query. Do not delete the semicolon or type anything following the SQL statement for the last select query.
-
On the Design tab, in the Results group, click Run.
The results of your union query appear in Datasheet view.
Watch an example of building a union query
Here is an example that you can recreate in the Northwind sample database. This union query collects the names of people from the Customers table and combines them with the names of people from the Suppliers table. If you'd like to follow along, work through these steps in your copy of the Northwind sample database.
Here are the steps necessary to build this example:
-
Create two select queries called Query1 and Query2 with the Customers and Suppliers tables respectively as data sources. Use First Name and Last Name fields as display values.
-
Create a new query called Query3 with no data source initially and then click the Union command on the Design tab to make this query into a Union query.
-
Copy and paste the SQL statements from Query1 and Query2 into Query3. Be sure to remove the extra semicolon and add in the UNION keyword. You can then check your results in datasheet view.
-
Add in an ordering clause into one of the queries and then paste the ORDER BY statement into the union query SQL view. Notice that in Query3, the union query, when the ordering is about to be appended, first the semicolons are removed, then the table name from the field names.
-
The final SQL that combines and sorts the names for this union query example is the following:
SELECT Customers.Company, Customers.[Last Name], Customers.[First Name] FROM Customers UNION SELECT Suppliers.Company, Suppliers.[Last Name], Suppliers.[First Name] FROM Suppliers ORDER BY [Last Name], [First Name];
If you're very comfortable writing SQL syntax, you can certainly write your own SQL statement for the union query directly into SQL view. However, you might find it useful to follow the approach of copying and pasting SQL from other query objects. Each query can be much more complicated than the simple select query examples used here. It can be to your advantage to create and test each query carefully before combining them in the union query. If the union query fails to run, you can adjust each query individually until it succeeds and then rebuild your union query with the corrected syntax.
Review the remaining sections of this article to learn more tips and tricks about using union queries.
Combine three or more tables or queries in a union query
In the example from the previous section using the Northwind database, only data from two tables are combined. However, you can combine three or more tables very easily in a union query. For example, building on the previous example, you might want to also include the names of the employees in the query output. You can accomplish that task by adding a third query and combining with the previous SQL statement with an additional UNION keyword like this:
SELECT Customers.Company, Customers.[Last Name], Customers.[First Name] FROM Customers UNION SELECT Suppliers.Company, Suppliers.[Last Name], Suppliers.[First Name] FROM Suppliers UNION SELECT Employees.Company, Employees.[Last Name], Employees.[First Name] FROM Employees ORDER BY [Last Name], [First Name];
When you view the result in datasheet view, all employees will be listed with the sample company name, which probably isn't very useful. If you want that field to indicate if a person is an in-house employee, from a supplier, or from a customer, you can include a fixed value in place of the company name. Here's how the SQL would look like:
SELECT "Customer" As Employment, Customers.[Last Name], Customers.[First Name] FROM Customers UNION SELECT "Supplier" As Employment, Suppliers.[Last Name], Suppliers.[First Name] FROM Suppliers UNION SELECT "In-house" As Employment, Employees.[Last Name], Employees.[First Name] FROM Employees ORDER BY [Last Name], [First Name];
Here's how the result appears in datasheet view. Access displays these five example records:
Employment | Last Name | First Name |
In-house | Freehafer | Nancy |
In-house | Giussani | Laura |
Supplier | Glasson | Stuart |
Customer | Goldschmidt | Daniel |
Customer | Gratacos Solsona | Antonio |
The query above can be reduced even further since Access only reads the names of the output fields from the first query in a union query. Here you see we've removed the output from the second and third query sections:
SELECT "Customer" As Employment, [Last Name], [First Name] FROM Customers UNION SELECT "Supplier", [Last Name], [First Name] FROM Suppliers UNION SELECT "In-house", [Last Name], [First Name] FROM Employees ORDER BY [Last Name], [First Name];
Filtering in union queries
In an Access union query, ordering is allowed only once but each query can be filtered individually. Building on the previous section's union query, here's an example of where we've filtered each query by adding a WHERE clause.
SELECT "Customer" As Employment, Customers.[Last Name], Customers.[First Name] FROM Customers WHERE [State/Province] = "UT" UNION SELECT "Supplier", [Last Name], [First Name] FROM Suppliers WHERE [Job Title] = "Sales Manager" UNION SELECT "In-house", Employees.[Last Name], Employees.[First Name] FROM Employees WHERE City = "Seattle" ORDER BY [Last Name], [First Name];
Switch to datasheet view and you'll see results similar to this:
Employment | Last Name | First Name |
Supplier | Andersen | Elizabeth A. |
In-house | Freehafer | Nancy |
Customer | Hasselberg | Jonas |
In-house | Hellung-Larsen | Anne |
Supplier | Hernandez-Echevarria | Amaya |
Customer | Mortensen | Sven |
Supplier | Sandberg | Mikael |
Supplier | Sousa | Luis |
In-house | Thorpe | Steven |
Supplier | Weiler | Cornelia |
In-house | Zare | Robert |
Mixing data types
If the queries to union are very different, you might encounter a situation where an output field must combine data of different data types. If so, the union query most often will return the results as a text data type since that data type can hold both text and numbers.
To understand how this works, we'll use the Product Transactions union query in the Northwind sample database. Open that sample database and then open the Product Transactions query in datasheet view. The last ten records should be similar to this output:
Product ID | Order Date | Company Name | Transaction | Quantity |
77 | 1/22/2006 | Supplier B | Purchase | 60 |
80 | 1/22/2006 | Supplier D | Purchase | 75 |
81 | 1/22/2006 | Supplier A | Purchase | 125 |
81 | 1/22/2006 | Supplier A | Purchase | 200 |
7 | 1/20/2006 | Company D | Sale | 10 |
51 | 1/20/2006 | Company D | Sale | 10 |
80 | 1/20/2006 | Company D | Sale | 10 |
34 | 1/15/2006 | Company AA | Sale | 100 |
80 | 1/15/2006 | Company AA | Sale | 30 |
Let's assume you want the Quantity field split into two - Buy and Sell. Let's also assume you want to have a fixed zero value for the field with no value. Here's how the SQL will look for this union query:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], 0 As Buy, [Quantity] As Sell FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] As Buy, 0 As Sell FROM [Product Purchases] ORDER BY [Order Date] DESC;
If you switch to datasheet view, you'll see the last ten records now displayed like the following:
Product ID | Order Date | Company Name | Transaction | Buy | Sell |
74 | 1/22/2006 | Supplier B | Purchase | 20 | 0 |
77 | 1/22/2006 | Supplier B | Purchase | 60 | 0 |
80 | 1/22/2006 | Supplier D | Purchase | 75 | 0 |
81 | 1/22/2006 | Supplier A | Purchase | 125 | 0 |
81 | 1/22/2006 | Supplier A | Purchase | 200 | 0 |
7 | 1/20/2006 | Company D | Sale | 0 | 10 |
51 | 1/20/2006 | Company D | Sale | 0 | 10 |
80 | 1/20/2006 | Company D | Sale | 0 | 10 |
34 | 1/15/2006 | Company AA | Sale | 0 | 100 |
80 | 1/15/2006 | Company AA | Sale | 0 | 30 |
Continuing this example, what if you want the fields with zero to be empty? You can modify the SQL to display nothing instead of zero by adding in the Null keyword like the following:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], Null As Buy, [Quantity] As Sell FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] As Buy, Null As Sell FROM [Product Purchases] ORDER BY [Order Date] DESC;
However, as you might have observed switching to datasheet view, you now have an unexpected result. In the Buy column, every field is cleared:
Product ID | Order Date | Company Name | Transaction | Buy | Sell |
74 | 1/22/2006 | Supplier B | Purchase |
|
|
77 | 1/22/2006 | Supplier B | Purchase |
|
|
80 | 1/22/2006 | Supplier D | Purchase |
|
|
81 | 1/22/2006 | Supplier A | Purchase |
|
|
81 | 1/22/2006 | Supplier A | Purchase |
|
|
7 | 1/20/2006 | Company D | Sale |
| 10 |
51 | 1/20/2006 | Company D | Sale |
| 10 |
80 | 1/20/2006 | Company D | Sale |
| 10 |
34 | 1/15/2006 | Company AA | Sale |
| 100 |
80 | 1/15/2006 | Company AA | Sale |
| 30 |
The reason this happens is because Access determines the data types of the fields from the first query. In this example, Null is not a number.
So what happens if you try and insert an empty string for the blank value of fields? The SQL for this attempt might look like the following:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], "" As Buy, [Quantity] As Sell FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] As Buy, "" As Sell FROM [Product Purchases] ORDER BY [Order Date] DESC;
When you switch to datasheet view, you'll see that Access retrieves the Buy values, but it converted the values to text. You can tell these are text values since they are left-aligned in the datasheet view. The empty string in the first query is not a number which is why you see these results. You'll also notice that the Sell values are also converted to text because the purchase records contain an empty string.
Product ID | Order Date | Company Name | Transaction | Buy | Sell |
74 | 1/22/2006 | Supplier B | Purchase | 20 |
|
77 | 1/22/2006 | Supplier B | Purchase | 60 |
|
80 | 1/22/2006 | Supplier D | Purchase | 75 |
|
81 | 1/22/2006 | Supplier A | Purchase | 125 |
|
81 | 1/22/2006 | Supplier A | Purchase | 200 |
|
7 | 1/20/2006 | Company D | Sale |
| 10 |
51 | 1/20/2006 | Company D | Sale |
| 10 |
80 | 1/20/2006 | Company D | Sale |
| 10 |
34 | 1/15/2006 | Company AA | Sale |
| 100 |
80 | 1/15/2006 | Company AA | Sale |
| 30 |
So how do you solve this puzzle?
A solution is to force the query to expect the field value to be a number. That can be accomplished with the expression:
IIf(False, 0, Null)
The condition to check, False, will never be True, thus the expression will always return Null, but Access still evaluates both output options and decides the output to be numeric or Null.
Here's how we can use this expression in our working example:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], IIf(False, 0, Null) As Buy, [Quantity] As Sell FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] As Buy, Null As Sell FROM [Product Purchases] ORDER BY [Order Date] DESC;
Note that it is not necessary to modify the second query.
If you switch to datasheet view, you'll now see a result that we want:
Product ID | Order Date | Company Name | Transaction | Buy | Sell |
74 | 1/22/2006 | Supplier B | Purchase | 20 |
|
77 | 1/22/2006 | Supplier B | Purchase | 60 |
|
80 | 1/22/2006 | Supplier D | Purchase | 75 |
|
81 | 1/22/2006 | Supplier A | Purchase | 125 |
|
81 | 1/22/2006 | Supplier A | Purchase | 200 |
|
7 | 1/20/2006 | Company D | Sale |
| 10 |
51 | 1/20/2006 | Company D | Sale |
| 10 |
80 | 1/20/2006 | Company D | Sale |
| 10 |
34 | 1/15/2006 | Company AA | Sale |
| 100 |
80 | 1/15/2006 | Company AA | Sale |
| 30 |
An alternative method to achieve the same result is to prepend the queries in the union query with yet another query:
SELECT 0 As [Product ID], Date() As [Order Date], "" As [Company Name], "" As [Transaction], 0 As Buy, 0 As Sell FROM [Product Orders] WHERE False
For each field, Access returns fixed values of the data type you define. Of course, you don't want the output of this query to interfere with the results so the trick to avoid that is to include a WHERE clause to False:
WHERE False
This is a little trick since this is always false and then the query doesn't return anything. Combining this statement with the existing SQL and we arrive at a completed statement as follows:
SELECT 0 As [Product ID], Date() As [Order Date], "" As [Company Name], "" As [Transaction], 0 As Buy, 0 As Sell FROM [Product Orders] WHERE False UNION SELECT [Product ID], [Order Date], [Company Name], [Transaction], Null As Buy, [Quantity] As Sell FROM [Product Orders] UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity] As Buy, Null As Sell FROM [Product Purchases] ORDER BY [Order Date] DESC;
Note: The combined query here in this example using the Northwind database returns 100 records, while the two individual queries return 58 and 43 records for a total of 101 records. The reason for this discrepancy is because two records are not unique. See the section, Working with distinct records in union queries using UNION ALL, to learn how to solve this scenario by using UNION ALL.
Adding totals in a union query
A special case for a union query is to combine a set of records with one record that contains the sum of one or more fields.
Here is another example that you can create in the Northwind sample database to illustrate how to get a total in a union query.
-
Create a new simple query to view the purchase of beers (Product ID=34 in the Northwind database) using the following SQL syntax:
SELECT [Purchase Order Details].[Date Received], [Purchase Order Details].Quantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=34)) ORDER BY [Purchase Order Details].[Date Received];
-
Switch to datasheet view and you should see four purchases:
Date Received
Quantity
1/22/2006
100
1/22/2006
60
4/4/2006
50
4/5/2006
300
-
To obtain the total, create a simple aggregating query using the following SQL:
SELECT Max([Date Received]), Sum([Quantity]) AS SumOfQuantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=34))
-
Switch to datasheet view and you should see only one record:
MaxOfDate Received
SumOfQuantity
4/5/2006
510
-
Combine these two queries into a union query to append the record with the total quantity to the purchase records:
SELECT [Purchase Order Details].[Date Received], [Purchase Order Details].Quantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=34)) UNION SELECT Max([Date Received]), Sum([Quantity]) AS SumOfQuantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=34)) ORDER BY [Purchase Order Details].[Date Received];
-
Switch to datasheet view and you should see the four purchases with the sum of each followed by a record that totals the quantity:
Date Received
Quantity
1/22/2006
60
1/22/2006
100
4/4/2006
50
4/5/2006
300
4/5/2006
510
That covers the basics of adding totals into a union query. You might also want to include fixed values in both queries such as "Detail" and "Total" to visually separate the total record from the other records. You can review using fixed values in the section Combine three or more tables or queries in a union query.
Working with distinct records in union queries using UNION ALL
Union queries in Access by default only include distinct records. But what if you want to include all records? Another example might be useful here.
In the previous section, we showed you how to create a total in a union query. Modify that union query SQL to include Product ID= 48:
SELECT [Purchase Order Details].[Date Received], [Purchase Order Details].Quantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=48)) UNION SELECT Max([Date Received]), Sum([Quantity]) AS SumOfQuantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=48)) ORDER BY [Purchase Order Details].[Date Received];
Switch to datasheet view and you should see a somewhat misleading result:
Date Received | Quantity |
1/22/2006 | 100 |
1/22/2006 | 200 |
One record of course doesn't return twice the quantity in total.
The reason you see this result is because on one day the same quantity of chocolates was sold twice - as recorded in the Purchase Order Details table. Here's a simple select query result showing both records in the Northwind sample database:
Purchase Order ID | Product | Quantity |
100 | Northwind Traders Chocolate | 100 |
92 | Northwind Traders Chocolate | 100 |
In the union query previously noted, you can see that the Purchase Order ID field isn't included and that the two fields don't make up two distinct records.
If you want to include all records, use UNION ALL instead of UNION in your SQL. This will mostly likely have an impact on the sorting of the results, so you might want to also include an ORDER BY clause to determine a sort order. Here's the modified SQL building off the previous example:
SELECT [Purchase Order Details].[Date Received], Null As [Total], [Purchase Order Details].Quantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=48)) UNION ALL SELECT Max([Date Received]), "Total" As [Total], Sum([Quantity]) AS SumOfQuantity FROM [Purchase Order Details] WHERE ((([Purchase Order Details].[Product ID])=48)) ORDER BY [Total];
Switch to datasheet view and you should see all the details in addition to a total as the last record:
Date Received | Total | Quantity |
1/22/2006 |
| 100 |
1/22/2006 |
| 100 |
1/22/2006 | Total | 200 |
Use a union query to filter records on a form through a combo box control
A common usage for a union query is to serve as the record source for a combo box control on a form. You can use that combo box to select a value to filter the form's records. For example, filtering the employee records by their city.
To see how this might work, here's another example that you can create in the Northwind sample database to illustrate this scenario.
-
Create a simple select query using this SQL syntax:
SELECT Employees.City, Employees.City AS Filter FROM Employees;
-
Switch to datasheet view and you should see the following results:
City
Filter
Seattle
Seattle
Bellevue
Bellevue
Redmond
Redmond
Kirkland
Kirkland
Seattle
Seattle
Redmond
Redmond
Seattle
Seattle
Redmond
Redmond
Seattle
Seattle
-
Looking at those results you might not see a lot of value. Expand the query though and transform it to a union query by using the following SQL:
SELECT Employees.City, Employees.City AS Filter FROM Employees UNION SELECT "<All>", "*" AS Filter FROM Employees ORDER BY City;
-
Switch to datasheet view and you should see the following results:
City
Filter
<All>
*
Bellevue
Bellevue
Kirkland
Kirkland
Redmond
Redmond
Seattle
Seattle
Access performs a union of the nine records, previously shown, with fixed field values of <All> and "*".
Since this union clause doesn't contain UNION ALL, Access returns only distinct records which means each city is returned only once with fixed identical values.
-
Now that you have a completed union query displaying each city name only once, along with an option that effectively selects all cities, you can use this query as the record source for a combo box on a form. Using this specific example as a model, you could create a combo box control on a form, set this query as its record source, set the Column Width property of the Filter column to 0 (zero) to hide it visually, and then set the Bound Column property to 1 to indicate the index of the second column. In the Filter property of the form itself, you can then add in code such as the following to activate a form filter using the value of what was selected in the combo box control:
Me.Filter = "[City] Like '" & Me![FilterComboBoxName].Value & "'" Me.FilterOn = True
The user of the form can then filter the form records to a specific city name or select <All> to list all records for all cities.
No comments:
Post a Comment