V
Vincent Johns
OK, here's a suggested (alternate) design for your Table structure.
Although I specified enforcing referential integrity for most links, I
did not do so with the [Person] Table, because it interfered with adding
new records.
All the primary keys (the ones identifying the record they're in) have
names consisting of the name of the Table, followed by "_ID". The
foreign keys (those used to refer to some other record) have similar
names, but possibly prefixed by a name suggesting what they contain,
such as [Parent_Person_ID] to refer to [Person_ID].
+----------+
|Person |
| _Client |
1|----------|
.--|Person_ID |
| +----------+
|
| +----------+ +------------+
| |Person | |Insurance |
| | _Child | | _Child | +---------+
| |----------|1 oo|------------| |Policy |
| oo|Person_ID |-----|Insured_ | | _Child |
+---|Parent_ | | Person_ID |1 oo|---------|
| | Person_ID| oo|Insurance_ID|------|Insurance|
| +----------+ .--|Company_ID | oo| _ID |
| : +------------+ .--|Detail_ID|
| : +---------+
| +-----------+ +------------+
| |Person | |Insurance |
| | _Spouse | | _Spouse | +---------+
| |-----------|1 oo|------------| |Policy |
| oo|Person_ID |-----|Insured_ | | _Spouse|
+---|Spouse_ | | Person_ID |1 oo|---------|
| | Person_ID| oo|Insurance_ID|------|Insurance|
| +-----------+ .--|Company_ID | oo| _ID |
| : +------------+ .--|Detail_ID|
| +------------+ : +---------+
| |Insurance |
| | _Client | +------------+
| oo|------------| |Policy |
'---|Insured_ | | _Client |
| Person_ID |1 oo|------------|
oo|Insurance_ID|-----|Insurance_ID|oo
.---|Company_ID | |Detail_ID |---.
| +------------+ +------------+ |
| |
| +----------+ +---------+ |
| |Company | |Detail | |
| 1|----------| |---------|1 |
'---|Company_ID| |Detail_ID|----'
+----------+ +---------+
Note: oo = "many" end of relationship
1 = "one" end of relationship
Example Tables follow, in alphabetical order. (In my own databases, I
define Lookup properties on all my foreign keys, to make the datasheets
easier to read. In this case I thought it might be better to show you
the raw key values stored in the Tables, so you could observe how they
link together.)
Each of the Tables probably needs additional fields.
This Table, as Tom Ellison suggested, lets you list each address just
once, to be shared by everyone living at that address. (Instead of
entering "836 SE 127th St." into each of several records, possibly
mistyping it, you select the number 12245183 from a list. Actually, the
user shouldn't see the number, but rather a list of addresses in a combo
box on a Form, with the option of entering a new address.)
[Address] Table Datasheet view:
Address_ID Address
---------- ------------------
12245183 836 SE 127th St.
155959414 666 Banshee Blvd.
173127785 1234 E. Main St.
The next Table does the same with insurance company names.
[Company] Table Datasheet view:
Company_ID Name
----------- -------
-1459391524 Everest
-78983385 Acme
This Table lists various perils that might be covered; each may appear
in multiple policies.
[Detail] Table Datasheet view:
Detail_ID Type
----------- ----------
940690545 Earthquake
443127896 Fire
-450676459 Flooding
-536392113 Hail
-1066305205 Hair loss
-2146535970 Lightning
-2001082702 Loss of nest
2001901126 Meteor strike
-492063696 Tooth decay
-512829575 Volcano
In the next Table, I couldn't determine what [Policy Owner] might be.
You can determine the contact person by following links. For example,
in a child's policy, [Insured_Person_ID] identifies the child, and that
record's [Parent_Person_ID] link identifies the client who owns the
policy. Or, this field could be a direct link to the owner's record,
but it's usually good to avoid storing redundant information in a Table,
because maintaining it takes unnecessary extra work.
The lines were a bit too wide for email, so I split the Table's listing,
repeating the primary key, [Insurance_ID], to help keep track of the
records. (It appears only once in each record.)
[Insurance] Table Datasheet view:
Insurance_ID Policy Company_ID Policy Life
Number Owner Insured
------------ ------ ----------- ------- -------
-1041598040 882-22 -1459391524 B. Bird No
-543328349 179-33 -78983385 Snuffy No
-242941295 600-28 -78983385 Ernie No
-9603188 882-57 -1459391524 Maria No
852585834 772-63 -1459391524 Oscar Yes
998160080 885-42 -1459391524 Bert No
2058552749 816-80 -1459391524 No
Insurance_ID Insured_Person_ID
------------ -----------------
-1041598040 8940911
-543328349 -1071790618
-242941295 -1737207726
-9603188 -1987616873
852585834 -2135742055
998160080 -2135742055
2058552749 453834372
The next Table includes records for all contacts, spouses, and children,
with links to other information such as address, parent, or spouse.
[Person] Table Datasheet view:
Person_ID Title First Middle Surname Sex
Name Name
----------- ----- ------- ------ ------- ---
-2135742055 Ms Mary A Jones F
-1987616873 Ms June Jones F
-1737207726 Colleen Smith F
-1071790618 Dr George Jones M
8940911 Tracy Q Jones F
453834372 Billy Jones M
1942089013 Mr Sydney Smith M
Person_ID Spouse_ Parent_ IsCon Address_ID
Person_ID Person_ID tact?
----------- ----------- ----------- ----- ----------
-2135742055 -2135742055 0 Yes 155959414
-1987616873 -2135742055 0 No 173127785
-1737207726 0 1942089013 No 12245183
-1071790618 0 Yes 173127785
8940911 0 -2135742055 No 173127785
453834372 0 -2135742055 No 173127785
1942089013 0 0 Yes 12245183
The next Table contains only some links, in each record identifying some
insurance policy and some detail (in my example, the name of a covered
hazard) in that policy.
[Policy] Table Datasheet view:
Policy_ID Insurance_ID Detail_ID
----------- ------------ ------------
-1772889958 -9603188 443127896
-1286666971 -242941295 -512829575
-742185598 852585834 2001901126
-511421815 -1041598040 -536392113
-478125093 852585834 443127896
-218923041 -543328349 -450676459
1000970262 -1041598040 -2001082702
1179632046 2058552749 -1066305205
1191726976 998160080 -492063696
1407383937 998160080 940690545
1450169396 -242941295 -2146535970
1722141597 -9603188 -492063696
Now, you may well ask, what good is it? Is there a way to get a
meaningful list from these Tables full of ugly-looking numbers? Fear
not, it should be easy. For example, the next Query lists all the
hazards in all the policies covering a child of one of the contacts.
Notice that I renamed some of the references to [Person] to reflect just
what kind of person the reference intended to reflect. For example,
[Child].[First Name] actually looks up the [Person].[First Name] field,
but calling it [Child] helps us remember that we're looking at a child's
name, instead of a spouse's name.
[Q_Children's Policies] SQL:
SELECT Contact.[First Name], Contact.Surname,
Child.[First Name], Child.Sex, Address.Address,
Company.Name, Insurance.[Policy Number],
Detail.Type
FROM ((Person AS Child INNER JOIN Address
ON Child.Address_ID = Address.Address_ID)
INNER JOIN Person AS Contact
ON Child.Parent_Person_ID = Contact.Person_ID)
INNER JOIN ((Insurance INNER JOIN Company
ON Insurance.Company_ID = Company.Company_ID)
INNER JOIN (Detail INNER JOIN Policy
ON Detail.Detail_ID = Policy.Detail_ID)
ON (Insurance.Insurance_ID = Policy.Insurance_ID)
AND (Insurance.Insurance_ID = Policy.Insurance_ID)
AND (Insurance.Insurance_ID = Policy.Insurance_ID))
ON (Child.Person_ID = Insurance.Insured_Person_ID)
AND (Child.Person_ID = Insurance.Insured_Person_ID)
AND (Child.Person_ID = Insurance.Insured_Person_ID)
WHERE (((Contact.[IsContact?])=Yes))
ORDER BY Contact.Surname, Child.[First Name];
The results of running this Query look like this (but again I had to
split the output, which was too wide for the page):
[Q_Children's Policies] Query Datasheet View:
Contact. Surname Child. Sex
First Name First Name
---------- ------- ---------- ---
Mary Jones Billy M
Mary Jones Tracy F
Mary Jones Tracy F
Sydney Smith Colleen F
Sydney Smith Colleen F
Address Name Policy Type
Number
---------------- ------- ------ ----------
1234 E. Main St. Everest 816-80 Hair loss
1234 E. Main St. Everest 882-22 Loss of nest
1234 E. Main St. Everest 882-22 Hail
836 SE 127th St. Acme 600-28 Volcano
836 SE 127th St. Acme 600-28 Lightning
Please bear in mind that, though I entered these imitation data by using
Table Datasheet View, your users should use Forms to perform that
function. Using a Form will allow you to check for obvious mistakes
while a user is entering data, so you can help protect the contents of
the Tables from damage. Access provides a Wizard to help you generate a
Form, once your Query is working properly.
There is also a Report Wizard that will help you design a Report so that
you can see a list which suppresses repeating information, such as the
street addresses or the sponsor's names.
-- Vincent Johns <[email protected]>
Please feel free to quote anything I say here.
Although I specified enforcing referential integrity for most links, I
did not do so with the [Person] Table, because it interfered with adding
new records.
All the primary keys (the ones identifying the record they're in) have
names consisting of the name of the Table, followed by "_ID". The
foreign keys (those used to refer to some other record) have similar
names, but possibly prefixed by a name suggesting what they contain,
such as [Parent_Person_ID] to refer to [Person_ID].
+----------+
|Person |
| _Client |
1|----------|
.--|Person_ID |
| +----------+
|
| +----------+ +------------+
| |Person | |Insurance |
| | _Child | | _Child | +---------+
| |----------|1 oo|------------| |Policy |
| oo|Person_ID |-----|Insured_ | | _Child |
+---|Parent_ | | Person_ID |1 oo|---------|
| | Person_ID| oo|Insurance_ID|------|Insurance|
| +----------+ .--|Company_ID | oo| _ID |
| : +------------+ .--|Detail_ID|
| : +---------+
| +-----------+ +------------+
| |Person | |Insurance |
| | _Spouse | | _Spouse | +---------+
| |-----------|1 oo|------------| |Policy |
| oo|Person_ID |-----|Insured_ | | _Spouse|
+---|Spouse_ | | Person_ID |1 oo|---------|
| | Person_ID| oo|Insurance_ID|------|Insurance|
| +-----------+ .--|Company_ID | oo| _ID |
| : +------------+ .--|Detail_ID|
| +------------+ : +---------+
| |Insurance |
| | _Client | +------------+
| oo|------------| |Policy |
'---|Insured_ | | _Client |
| Person_ID |1 oo|------------|
oo|Insurance_ID|-----|Insurance_ID|oo
.---|Company_ID | |Detail_ID |---.
| +------------+ +------------+ |
| |
| +----------+ +---------+ |
| |Company | |Detail | |
| 1|----------| |---------|1 |
'---|Company_ID| |Detail_ID|----'
+----------+ +---------+
Note: oo = "many" end of relationship
1 = "one" end of relationship
Example Tables follow, in alphabetical order. (In my own databases, I
define Lookup properties on all my foreign keys, to make the datasheets
easier to read. In this case I thought it might be better to show you
the raw key values stored in the Tables, so you could observe how they
link together.)
Each of the Tables probably needs additional fields.
This Table, as Tom Ellison suggested, lets you list each address just
once, to be shared by everyone living at that address. (Instead of
entering "836 SE 127th St." into each of several records, possibly
mistyping it, you select the number 12245183 from a list. Actually, the
user shouldn't see the number, but rather a list of addresses in a combo
box on a Form, with the option of entering a new address.)
[Address] Table Datasheet view:
Address_ID Address
---------- ------------------
12245183 836 SE 127th St.
155959414 666 Banshee Blvd.
173127785 1234 E. Main St.
The next Table does the same with insurance company names.
[Company] Table Datasheet view:
Company_ID Name
----------- -------
-1459391524 Everest
-78983385 Acme
This Table lists various perils that might be covered; each may appear
in multiple policies.
[Detail] Table Datasheet view:
Detail_ID Type
----------- ----------
940690545 Earthquake
443127896 Fire
-450676459 Flooding
-536392113 Hail
-1066305205 Hair loss
-2146535970 Lightning
-2001082702 Loss of nest
2001901126 Meteor strike
-492063696 Tooth decay
-512829575 Volcano
In the next Table, I couldn't determine what [Policy Owner] might be.
You can determine the contact person by following links. For example,
in a child's policy, [Insured_Person_ID] identifies the child, and that
record's [Parent_Person_ID] link identifies the client who owns the
policy. Or, this field could be a direct link to the owner's record,
but it's usually good to avoid storing redundant information in a Table,
because maintaining it takes unnecessary extra work.
The lines were a bit too wide for email, so I split the Table's listing,
repeating the primary key, [Insurance_ID], to help keep track of the
records. (It appears only once in each record.)
[Insurance] Table Datasheet view:
Insurance_ID Policy Company_ID Policy Life
Number Owner Insured
------------ ------ ----------- ------- -------
-1041598040 882-22 -1459391524 B. Bird No
-543328349 179-33 -78983385 Snuffy No
-242941295 600-28 -78983385 Ernie No
-9603188 882-57 -1459391524 Maria No
852585834 772-63 -1459391524 Oscar Yes
998160080 885-42 -1459391524 Bert No
2058552749 816-80 -1459391524 No
Insurance_ID Insured_Person_ID
------------ -----------------
-1041598040 8940911
-543328349 -1071790618
-242941295 -1737207726
-9603188 -1987616873
852585834 -2135742055
998160080 -2135742055
2058552749 453834372
The next Table includes records for all contacts, spouses, and children,
with links to other information such as address, parent, or spouse.
[Person] Table Datasheet view:
Person_ID Title First Middle Surname Sex
Name Name
----------- ----- ------- ------ ------- ---
-2135742055 Ms Mary A Jones F
-1987616873 Ms June Jones F
-1737207726 Colleen Smith F
-1071790618 Dr George Jones M
8940911 Tracy Q Jones F
453834372 Billy Jones M
1942089013 Mr Sydney Smith M
Person_ID Spouse_ Parent_ IsCon Address_ID
Person_ID Person_ID tact?
----------- ----------- ----------- ----- ----------
-2135742055 -2135742055 0 Yes 155959414
-1987616873 -2135742055 0 No 173127785
-1737207726 0 1942089013 No 12245183
-1071790618 0 Yes 173127785
8940911 0 -2135742055 No 173127785
453834372 0 -2135742055 No 173127785
1942089013 0 0 Yes 12245183
The next Table contains only some links, in each record identifying some
insurance policy and some detail (in my example, the name of a covered
hazard) in that policy.
[Policy] Table Datasheet view:
Policy_ID Insurance_ID Detail_ID
----------- ------------ ------------
-1772889958 -9603188 443127896
-1286666971 -242941295 -512829575
-742185598 852585834 2001901126
-511421815 -1041598040 -536392113
-478125093 852585834 443127896
-218923041 -543328349 -450676459
1000970262 -1041598040 -2001082702
1179632046 2058552749 -1066305205
1191726976 998160080 -492063696
1407383937 998160080 940690545
1450169396 -242941295 -2146535970
1722141597 -9603188 -492063696
Now, you may well ask, what good is it? Is there a way to get a
meaningful list from these Tables full of ugly-looking numbers? Fear
not, it should be easy. For example, the next Query lists all the
hazards in all the policies covering a child of one of the contacts.
Notice that I renamed some of the references to [Person] to reflect just
what kind of person the reference intended to reflect. For example,
[Child].[First Name] actually looks up the [Person].[First Name] field,
but calling it [Child] helps us remember that we're looking at a child's
name, instead of a spouse's name.
[Q_Children's Policies] SQL:
SELECT Contact.[First Name], Contact.Surname,
Child.[First Name], Child.Sex, Address.Address,
Company.Name, Insurance.[Policy Number],
Detail.Type
FROM ((Person AS Child INNER JOIN Address
ON Child.Address_ID = Address.Address_ID)
INNER JOIN Person AS Contact
ON Child.Parent_Person_ID = Contact.Person_ID)
INNER JOIN ((Insurance INNER JOIN Company
ON Insurance.Company_ID = Company.Company_ID)
INNER JOIN (Detail INNER JOIN Policy
ON Detail.Detail_ID = Policy.Detail_ID)
ON (Insurance.Insurance_ID = Policy.Insurance_ID)
AND (Insurance.Insurance_ID = Policy.Insurance_ID)
AND (Insurance.Insurance_ID = Policy.Insurance_ID))
ON (Child.Person_ID = Insurance.Insured_Person_ID)
AND (Child.Person_ID = Insurance.Insured_Person_ID)
AND (Child.Person_ID = Insurance.Insured_Person_ID)
WHERE (((Contact.[IsContact?])=Yes))
ORDER BY Contact.Surname, Child.[First Name];
The results of running this Query look like this (but again I had to
split the output, which was too wide for the page):
[Q_Children's Policies] Query Datasheet View:
Contact. Surname Child. Sex
First Name First Name
---------- ------- ---------- ---
Mary Jones Billy M
Mary Jones Tracy F
Mary Jones Tracy F
Sydney Smith Colleen F
Sydney Smith Colleen F
Address Name Policy Type
Number
---------------- ------- ------ ----------
1234 E. Main St. Everest 816-80 Hair loss
1234 E. Main St. Everest 882-22 Loss of nest
1234 E. Main St. Everest 882-22 Hail
836 SE 127th St. Acme 600-28 Volcano
836 SE 127th St. Acme 600-28 Lightning
Please bear in mind that, though I entered these imitation data by using
Table Datasheet View, your users should use Forms to perform that
function. Using a Form will allow you to check for obvious mistakes
while a user is entering data, so you can help protect the contents of
the Tables from damage. Access provides a Wizard to help you generate a
Form, once your Query is working properly.
There is also a Report Wizard that will help you design a Report so that
you can see a list which suppresses repeating information, such as the
street addresses or the sponsor's names.
-- Vincent Johns <[email protected]>
Please feel free to quote anything I say here.
Vincent said:Hello, kingnothing, I'm back...
At the risk of reiterating my previous comments, I don't agree with your
"apart from...", since maintaining those separate but largely isomorphic
Tables implies that you'll later be essentially REQUIRED to do a lot of
work destroying them (=moving their contents to a well-designed Table),
after you've done work building them, when you could do that right now,
while you're still designing the things and haven't invested lots of
effort into populating them. Several people have given you good advice.
It's possible to do useful work with poorly designed Tables, but it
takes (maybe much) more effort than necessary.
The self-joins that jacksonmacd and maybe others have suggested
shouldn't be that scary, especially if you're working in Query Design
View. You can even rename the extra views of your Table -- just
right-click on the Table in the upper portion, choose Properties, and
enter a new name into the Alias field. It's still a reference to the
same Table, but it looks in Query Design View like a different Table.
You mentioned that you want to keep things simple. That's a good idea;
as mnature suggested, tracking all possible relationships (maybe to a
dozen generations) will take work and maybe be unnecessary. One virtue
of a RDBMS like Access is that it's pretty flexible. You can start with
a simple model, get it working, then as you discover that you need to
model additional information, it's often not difficult to extend your
original design to take care of that. I've never had to throw away an
Access database because of its becoming unmaintainable. (I have,
however, had to throw away Tables and other objects at times... but
that's not quite as drastic.)
Anyway, I have a few minutes, so I'll try to post another message soon
showing you a bit more graphically what others & I are trying to suggest
that you do.
-- Vincent Johns <[email protected]>
Please feel free to quote anything I say here.
Yeah i know about referential intergrity. so, you are saying that
relationships are absolutely imperative for the database design,
right!! Please look at http://members.westnet.com.au/mukund/rel.gif
and tell if if
there is anything wrong with the way the database is designed (Apart
form the
fact that i will be storing simillar records in different tables)
PS: if you want a clearer picture let me know, i can make another one
Regards,
kingnothing
Tom said:Dear Kingnothing:
Putting the relationships into the table design is an essential.
There is something called referential integrity.
If you have a one-to-many relationship you must not allow the rows on
the many side to be "orphaned". That means, you cannot delete a row
in the table on the "one" side when there are rows on the "many"
side. You must either delete them, too, or prohibit deleting the
"one". That's the job of referential integrity. Try it! You'll see
what I mean.
So then, without enforcing referential integrity, there is little
likelihood the database will work well later when you write those
queries.
Tom Ellison
Please see inline..
[quoted text clipped - 51 lines]
kingnothing