Documenting query dependencies
If you have to document the queries on your database you will
often need to know:
- What queries do I have in the database, and what is the SQL
for those queries? - What queries and tables in the database lie upstream of any
query; ie, what data does my query depend on?
In an earlier article I showed
how to document query SQL.
This article builds on that documentation to answer the second
question.
Query dependencies — built-in options
Access has a built-in option for viewing object dependencies, if
you have version 2003 or higher. It requires you to turn on a
feature called Name Auto-correct which has a reputation for causing
problems with forms, queries, reports and general database
performance, as well as contributing to database crashes (see
link). The
feature is enabled by default and the current recommendation is that
you turn it off. If you do decide to use Name Autocorrect, be aware
of the risks.
Viewing object dependencies in Access 2003
To view object dependencies in Access 2003, do the following:
- Select an object (Table, Query, Form or Report) from the
list on the left of the database container. - Select View | Object Dependencies. If the Name Autocorrect
feature is turned off you will get a warning that the feature
will be turned on, and that you may have a delay of several
minutes. Click OK. You will see a new pane at the right of the
database window, with all of the objects that depend on the one
you selected. You can toggle the view to see objects on which
your selected object depends. - If you select another object, go back to View | Object
Dependencies and the pane will refresh.
Viewing object dependencies in Access 2007
- Select an object from the list on the left of the database
window. - In the Database Tools ribbon, select Object Dependencies
from the Show/Hide group. You will get the same warning as from
Access 2003 (above); click OK and the pane will appear at the
right of the database window. - If you select another object, click Refresh on the pane to
update the dependencies.
Turning off Name Autocorrect in Access 2000-2003
To turn off Name AutoCorrect do the following:
- Go to Tools | Options | General
- In the Name Autocorrect section (right hand side, halfway
down), deselect the options
Turning off Name Autocorrect in Access 2007
In Access 2007, you turn off Name Autocorrect by doing the
following:
- Click the Office button at the top left of the screen, and
then select the Access Options at the bottom of the dialog - Select the Current Database button, and scroll to the bottom
of the form. Deselect any options in the Name Autocorrect
section and click OK. You may be prompted to restart the
database before your changes take effect.
Query dependencies — do it yourself
To document your queries so that you can see the dependencies in
any version from 2000 up, you can add another couple of functions
and a new form to the original method.
First, you will need to modify the design of ztblQueries and
create a new table called ztblReferencedQueries, which holds the
relationship data. If you haven’t used
the code for documenting
tables you will also need to create ztblTables and run the
WriteTableList function below.
The modified query table: ztblQueries
Field | Data Type | Comments |
---|---|---|
qryID | AutoNumber | Primary Key |
QueryName | Text (255) | |
QuerySQL | Memo | |
QueryType | Number |
The modified table has one additional field: a Number field
called QueryType.
A table for the relationship data: ztblReferencedQueries
Field | Data Type | Comments |
---|---|---|
RefID | AutoNumber | Primary Key |
QueryName | Text (255) | |
RefName | Text (255) | |
Relationship | Text (50) |
A table that lists the tables in the database: ztblTables
Field | Data Type | Comments |
---|---|---|
TableName | Text (255) |
The code
The first routine writes a list of tables — we’ll use this for
checking references to tables later on. Once existing records are
deleted, the function loops through the TableDefs collection, adding
the names of any tables that are not system, utility or temp tables.
Function WriteTableList() ''========================================================='' ''Writes name of all tables ''to ztblTables. Table is cleared first. ''========================================================='' Dim dbs As DAO.Database Dim rst As DAO.Recordset Dim tdf As DAO.TableDef Dim sSQL As String sSQL = "DELETE * FROM ztblTables" 'Clear out ztblTables to avoid duplication DoCmd.SetWarnings False DoCmd.RunSQL sSQL DoCmd.SetWarnings True Set dbs = CurrentDb() Set rst = dbs.TableDefs("ztblTables").OpenRecordset 'Add table names to ztblTables. The If statement excludes system tables (MSYS*), 'utility tables used in the documentation process (z*), and 'temporary tables caused by deletion of tables in other routines (~*) For Each tdf In dbs.TableDefs 'exclude system, temp and accessory tables If Left(tdf.Name, 4) <> "MSYS" _ And Left(tdf.Name, 1) <> "z" _ And Left(tdf.Name, 1) <> "~" Then rst.AddNew rst!tableName = tdf.Name rst.Update End If Next tdf 'cleanup rst.Close Set rst = Nothing Set tdf = Nothing Set dbs = Nothing End Function
The second routine
(and the ztblQueries table) are documented in the previous article.
The code runs
through all queries, writing the query name, SQL and query type to
ztblQueries.
Once these two routines have run, the third routine (below)
populates ztblReferencedQueries.
Function ReferencesInQueries() ''========================================================='' ''Runs through query names in ztblQueries to see what tables ''and queries are referenced. Any that are found are written ''out to ztblReferencedQueries ''Written 11 Sep 2007 by Denis Wright ''Modified 12 Sep 2007 to account for parent and child references ''========================================================='' Dim dbs As DAO.Database Dim rstMain As DAO.Recordset Dim rstTable As DAO.Recordset Dim rstQuery As DAO.Recordset Dim x, y 'arrays to hold split data Dim sCheckParent As String, _ sCheckChild As String Dim bChild As Boolean 'define recordsets Set dbs = CurrentDb() Set rstMain = dbs.CreateQueryDef("", "SELECT * FROM ztblQueries").OpenRecordset Set rstTable = dbs.CreateQueryDef("", "SELECT TableName FROM ztblTables").OpenRecordset Set rstQuery = dbs.CreateQueryDef("", "SELECT QueryName FROM ztblQueries").OpenRecordset DoCmd.SetWarnings False 'clean out existing data DoCmd.RunSQL "DELETE * FROM ztblReferencedQueries" 'loop through all queries, checking against table and query names With rstMain .MoveFirst Do Until .EOF bChild = False If rstMain!QueryType = 80 Then 'Make-table query bChild = True x = Split(rstMain!QuerySQL, "FROM") y = Split(x(0), "INTO") sCheckChild = y(1) sCheckParent = y(0) ElseIf rstMain!QueryType = 64 Then 'Append query bChild = True x = Split(rstMain!QuerySQL, "SELECT") sCheckChild = x(0) sCheckParent = x(1) Else sCheckParent = rstMain!QuerySQL End If 'loop through all table names With rstTable .MoveFirst Do Until .EOF If bChild Then Call AddRefRecord(sCheckChild, rstTable!tableName, _ rstMain!QueryName, "Child") End If Call AddRefRecord(sCheckParent, rstTable!tableName, _ rstMain!QueryName, "Parent") .MoveNext Loop End With 'loop through all query names With rstQuery .MoveFirst Do Until .EOF If bChild Then Call AddRefRecord(sCheckChild, rstQuery!QueryName, _ rstMain!QueryName, "Child") End If Call AddRefRecord(sCheckParent, rstQuery!QueryName, _ rstMain!QueryName, "Parent") .MoveNext Loop End With .MoveNext Loop End With DoCmd.SetWarnings True 'clean up references rstQuery.Close rstTable.Close rstMain.Close Set rstQuery = Nothing Set rstTable = Nothing Set rstMain = Nothing Set dbs = Nothing End Function
To describe what the code is doing, let’s take a look at how it
deals with a make-table query. Assuming that we have a query called
qmakCustomers_AtoM, with this SQL:
SELECT Customers.*, Customers.CompanyName INTO Customers_AtoM FROM Customers WHERE (((Customers.CompanyName)<"N*"));
This part of the code splits the SQL statement into three
sections (Split takes an input string and a delimiter, and creates a
zero-based array of the substrings):
If rstMain!QueryType = 80 Then 'Make-table query bChild = True x = Split(rstMain!QuerySQL, "FROM") y = Split(x(0), "INTO") sCheckChild = y(1) sCheckParent = y(0)
The first split results in the following 2 strings:
Array element | String |
---|---|
x(0) | SELECT Customers.*, Customers.CompanyName INTO Customers_AtoM |
x(1) | Customers WHERE (((Customers.CompanyName)<"N*")); |
The first array element holds the two pieces of information that
we want from the SQL: the parent (source) and the child (dependent
table / query). By splitting x(0) again using INTO as the delimiter,
we end up with:
Array element | String |
---|---|
y(0) | SELECT Customers.*, Customers.CompanyName |
y(1) | Customers_AtoM |
These two elements are then processed by the AddRefRecord
function, which creates a new record in ztblReferencedQueries for
each parent / child pair. The code for AddRefRecord is shown below.
The error handling creates the table if it doesn't already exist,
and the INSERT statement adds the new record.
Function AddRefRecord(sTestString As String, sCompareString As String, sQueryName As String, _ sRelationship As String) As Boolean Dim sSQL As String 'this SQL creates ztblReferencedQueries on the fly if it doesn't exist sSQL = "CREATE TABLE ztblReferencedQueries ( " _ & "RefID COUNTER, " _ & "ObjectName TEXT(225), " _ & "RefName TEXT (255), " _ & "Relationship TEXT(30)); " On Error GoTo Err_Handle AddRefRecord = False If InStr(1, sTestString, sCompareString) > 0 Then 'add the new record DoCmd.SetWarnings False DoCmd.RunSQL "INSERT INTO ztblReferencedQueries ( ObjectName,RefName,Relationship,ObjectType ) " _ & "VALUES ('" & sQueryName & "','" & sCompareString & "' _ & ",'" & sRelationship & "','" & sObjectType & "')" DoCmd.SetWarnings True AddRefRecord = True End If Err_Exit: Exit Function Err_Handle: Select Case Err.Number Case 3192 'Table does not exist 'create the table, then continue DoCmd.SetWarnings False DoCmd.RunSQL sSQL DoCmd.SetWarnings True Resume Next Case Else MsgBox "Error " & Err.Number & ": " & Err.Description Resume Err_Exit End Select End Function