|
|
|
|
Relationship Constant |
Integer Value |
Description |
Sub DSheet |
|
dbRelationDontEnforce |
2 |
Simple Join. The relationship isn't enforced (no referential integrity). |
No |
|
DbRelationEnforce |
0 |
Enforce Referential Integrity |
Yes |
|
dbRelationDeleteCascade |
4096 |
Delete Cascade |
Yes |
|
dbRelationInherited |
4 |
Inherited referential integrity from another database |
No |
|
dbRelationRight |
33554432 |
Right Join |
No |
|
dbRelationLeft |
16777216 |
Left join |
No |
|
dbRelationUnique |
1 |
One to one |
Yes |
|
dbRelationUpdateCascade |
256 |
Update Cascade |
Yes |
Table 1 - Relationships constants and whether they will produce a subdatasheet
Now I wanted to generate my own relationship so that I could add a subdatasheet programmatically. To do this I had to find out how to build a relationship using visual basic. In Access 2000 it wasn't easy because none of the help on relationships showed any visual basic examples. When I returned to Access 97, the createRelationship method of the Microsoft DAO Library finally appeared in the help results. So the lesson there is return to Access 97 if your help may need DAO functions. For the examples that follow, you will need to include a reference to the DAO 3.X library in your project.
The Consolidation Query - Detail Example
As some of those who have read my previous articles would know, I have a soft spot for consolidation queries. To further illustrate the techniques for building your own subdatasheets, I am going to produce a query where you can drilldown on the consolidation groups to see the detail records.
Relationship Building Source Code
The visual basic that handles this code uses a combination of DAO methods and good old SQL to generate the output. Initially I first have to make a new table as referential relationships such as Cascade updates can only occur between tables and the primary table must have a unique key. The 2 SQL statements that I use are a Make Table query and then a Create Index query with a Primary Key clause.
' Run a make table consolidation query
sqlStr = "SELECT
ProductName," & _
" Sum(Sales) AS SumSales" & _
" INTO TotalProducts FROM zWorldDemo
" & _
" GROUP BY ProductName;"
DoCmd.RunSQL sqlStr
' Now create a relationship
between the consolidation
' table and the original data by first creating a
' primary index on the new table and then creating
' the relationship
sqlStr = "CREATE
UNIQUE INDEX " & _
" MyIndex ON TotalProducts (productName) With Primary"
DoCmd.RunSQL sqlStr
Now I to generate a Cascade Delete relationship between the new table called TotalProducts and the corresponding group by field in the detail table called "zWorldDemo". This first involves creating a RelationObject which I have given the name "My Relationship". To see the different types of joins that you can use in the relationship, see the constants in Table 1. Once you have established the relationship you will need to add a field to the new relation object and define which field is to be used in the foreign table.
Dim sqlStr As String
Dim dbsRelate As DAO.Database
Dim relNew As DAO.Relation
Set dbsRelate = CurrentDb
Set relNew = dbsRelate.CreateRelation("MyRelationship", _
"TotalProducts",
"zWorldDemo", _
dbRelationUpdateCascade)
With relNew
' Need to create a field in relation object prior
to
' defining the name of the external field.
.Fields.Append relNew.CreateField("ProductName")
.Fields!productName.ForeignName =
"ProductName"
dbsRelate.Relations.Append relNew
DoCmd.OpenTable
"TotalProducts", , acReadOnly
dbsRelate.Close
Prior to running all this code, you will need to delete the relationship and the consolidation table in case they exist in the database
On Error Resume Next
' Clean up the initial relationships in case they exist
Set dbsRelate = CurrentDb
With dbsRelate
.Relations.Delete
"MyRelationship"
.Close
End With
' Remove the old consolidation output table
sqlStr = "drop table
TotalProducts"
DoCmd.RunSQL sqlStr
On Error GoTo 0
The Penny Drops - All About The New Subdatasheet Property
If you already know a little about subdatasheets, you probably wonder why I went through the pain of creating a relationship to generate the subdatasheets. Well I just came across no explanation in many hours of using Access 2000 to suggest that this was anything more than an undocumented feature. That was until I opened the table called tlkp_Referral which has 2 one to many relationships (see figure 3). This brought up a wizard that asked me to define which table and field I wished to use as my subdatasheets fields. This accident taught me that I should look for help on subdatasheets which on the whole is really quite good.

Figure 5 - Defining a join for a subdatasheet
So to add a subdatasheet manually, here are the surprising facts. You are not required to add a relationship at all and there is no requirement to use primary keys and tables. In summary, you can make subdatasheet join between 1 or more fields in the same way as you can define master and child fields in a subform.
So without laboring too much over the manual techniques, here are the methods you can use.
For a table or query, open the table in data entry mode and choose the Insert Menu à now select Subdatasheet and you will get the same wizard as shown in figure 5.
Once you have a subdatasheet established, you can click on the Format menu and choose Subdatasheet from the menu. This will give the option of removing the subdatasheet, expanding all subdatasheet rows so that you see all the detail rows and turning expand rows off again.
You can also control the maximum height that is used to display the subdatasheets by simply resizing the row manually with your mouse. This allows you to see the first 2-3 rows rather than every row.
But the feature that I really like is that you can actually perform filters on the subdatasheets. This means that you can really explore your data in a fashion that you used to only ever achieve with forms and subforms. The advantage is far less code and less onscreen clutter.
Behind The Scenes - The Subdatasheet Properties
When you use these manual commands or
wizards, Access modifies the 5 new properties in the Table or Query definition.
If you open a table in design mode and click on properties as shown in
figure 6, you can see the properties that control
how your subdatasheet is displayed. Queries
have exactly the same properties.

Figure 6 - The subdatasheet properties that control the display
Setting All The Properties In Visual Basic
The online help for the manual manipulation of subdatasheets is pretty good except for the bit where it says you can control the properties in visual basic. Then you have to search all over the place for the code to control the properties of a table and a query. Given that it is in the DAO library, I once again found it in Access 97 help. But you don't have to worry because here is all the code you need to set the subdatasheet properties for a query.
addOK =
subDataSheetQry_FX("qrySumProducts", _
"zWorldDemo", "ProductName", "ProductName", True,
1100)
The subDataSheetQry_FX function passes all the 5 required properties to the following function which has option arguments for the expanding and height properties. This function then calls another function to modify the 5 subdatasheet properties. Code snippets follow.
Function
subDataSheetQry_FX( _
qryName As String, SubDSName As String, _
LinkChild
As String, LinkMaster As String, _
Optional
subDSExpand, Optional subDSHeight) As Boolean
subDS_OK
= qryPropMod_FX(qryName,
"SubdatasheetName", SubDSName)
' Etc Etc - Now demonstrate the optional arguement
If
Not IsMissing(subDSHeight) Then
subDS_OK = qryPropMod_FX(qryName, _
"SubdatasheetHeight",
subDSHeight)
End
If
But the really tricky code is setting the properties and the main reason I floundered is that I was caught by the dual ADO and DAO library issue. The methods to manage properties is also supported to some extent in ADO and because I had set my reference to DAO after ADO, the property setting methods were mixed up between ADO and DAO and I received errors that simply set me off on the wrong track for a number of hours. So if you haven't already done it, start working through your Access 97 code and adding the "DAO." prefix to all your DAO methods and properties or you are just going to get caught like I was.
So the function that sets the Query property works by first trying to modify the existing property value.
Dim dbs As DAO.Database, qdf As DAO.QueryDef
Dim prp As DAO.property
Const conPropNotFound As Integer = 3270
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs(qryName)
' Enable error handling.
qdf.Properties(propertyStr) = valStr
dbs.QueryDefs.Refresh
qryPropMod_FX = True
Exit Function
If the property does not exist, the error is trapped and the property is instead appended to the query properties collection. The CreateProperty method has a second optional argument where you can set the data type of the property. As the subdatasheet properties are a mixture of dbText, dbInteger and dbBoolean constants, I ended up using the dbText as a common constant unless the CreateProperty Method crashed as was the case for the Expanded property. The help says this data type is an optional argument but I am not sure when it is optional so you just have to work out what to set by trial and error.
queryPropertyMod_Fail:
' Check number of error that has occurred.
If Err.Number = conPropNotFound Then
'
The property does not exist, add it
Select
Case propertyStr
Case "SubdatasheetExpanded"
propType
= dbBoolean
Case Else
propType
= dbText
End Select
Set prp = qdf.CreateProperty(propertyStr, propType, valStr)
qdf.Properties.Append prp
Resume Next
Else
' If different error has occurred, display message.
MsgBox "Error Handler
---> " & Error, vbCritical, _
"Unknown error in
qryPropMod_FX function ... Query =
" _
& qryName & "
Property = " & propertyStr & "
value = " & valStr
qryPropMod_FX = False
End If
The Consolidation Query and The Detail
Finally has the linking of consolidation query to the detail been worth it. Well have a look at the query that is shown in figure 7. This shows the totals in the greyed lines. I even put in a couple of null fields to allow the totals to align with the detail. The detail shows the last 3 entries (reverse sorted date) which I applied by sorting the subdatasheet. So we have ended up with a report that looks like a spreadsheet (which will please a lot of end users) that shows totals and detail. All that for the cost of developing a query and linking using the subdatasheet properties.

Figure 7 - A consolidation query shown in grey linked to the detail records that it.
To
test all the subroutines explained above, I have incorporated the subdatasheet
methods into the latest version of my data mining program Graf-FX.
The findings that I can draw from that programming exercise are that
·
You
can actually keep the code in an Access 97 database and the properties will be
added to the queries with absolutely no effect on your application.
This is great if you are still developing in Access 97 (like Graf-FX) but
would like to add this flexibility for your Access 2000 customers.
·
When
you use a query with a where clause, be careful that the records that you join
to are filtered as well or you may end up with all matching records rather than
just the records that should be filtered.
·
You
can add a subdatasheet to a crosstab/pivot query just as for a normal query.
This is pretty amazing as far as I am concerned.
Conclusion
For those of you who have read articles on ADO data shaping and used the controls such as the flex grid control, you will realise that the subdatasheet is a very powerful end user object that doesn't require anywhere near the work of these programmable objects. The really good thing about subdatasheets is that you can manually set up the subdatasheet in your application or turn it into an analysis tool with not much more than an openTable statement and read-only statement.
If you require a flexible reporting environment, you can either add a relationship programmatically to your application or you can manipulate the subdatasheet properties using the functions that I have provided. This will give your users some wonderful tools to explore their data with.
As for my projects, when I complete the data modelling phase of my projects, I will convert my Data Exploration form with its OpenTable commands and Lookup table viewer into a data exploration interface for the users by simply opening all the tables in readonly mode. Now I will not have to throw away that useful form.
So though the setting up of subdatasheets will generally have to be done by developers or power users, this new tool is a real bonus to end users and deserves 5 out 5 stars. I only wish the extensions to tables and queries had been more obvious to me. I also wish that I had read Mike Gunderoloy's article on Subdatasheets which was printed in Smart Access in November, 1999. Luckily I can claim distracted "father to be" syndrome for this slip in my knowledge exploration.
Michael Gunderloy "Power Up with Subdatasheets" in November 1999 and "Data shaping" in December, 1999.
Michael Kaplan and Karleen Smith "DAO verses ADO discussions " in August 1999
Garry Robinson "Consolidation Queries" in October of 1998
Garry Robinson "Using Access Filters to Graph and Explore Your Databases"
http://www.vb123.com/toolshed/99docs/drilldownfilters.htm
Author
Bio.
Garry Robinson is the founder of GR-FX Pty Limited, a company based in Sydney,
Australia. If you want to keep up to date with the his latest postings on Access
Issues, visit his companies web
site at http://www.gr-fx.com/
or
The demonstration database is only applicable to Access 2000.
Other Pages On This Site You Might Like To Read
Consolidation Queries
Data Mining Using MS Access
Transaction Queries
Using Access Filters to Graph and Explore Your Databases
Implementing a Successful Multi-user
Access/JET Application
Click here for the
download file if you own "The Toolshed" Else click
here
| This article first appeared in the
June 2000 Edition of
Smart Access. Reprinted with permission from Pinnacle Publishing (http://www.pinpub.com). and was written by Garry Robinson from GR-FX Pty Limited |
Click on the following button
to jump to the next page in the document loop.
|
Links >>> Home | Search | Workbench | Orders | Newsletter | Access Security | Access professionals |