Severe relationship problem: change the key field? (1 Viewer)

vangogh228

Registered User.
Local time
Yesterday, 21:07
Joined
Apr 19, 2002
Messages
302
I have inherited a database that has a problem I do not know how to fix. The database holds the demographic information on individuals and has related tables with one-to-many relationships. The key field is the SSN. This has not created any problems until it was discovered that a couple of the SSNs were input incorrectly, and the records had related information in the related tables.

To fix this, the admin user created a dummy record and moved all the underlying data to the dummy, then changed the main SSN to the correct number, then went back to the underlying data and changed them to relate to the corrected record.

I believe the SSN should not be the key field, or the related field, and I bleieve the main table needs an autonumber field, but I am not sure how to resolve this and keep the relationships intact.

The names of the tables are MAIN, MEDICAL, PSYCH, FAMILY and NOTES.

ANY help is greatly appreciated.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 20:07
Joined
Feb 28, 2001
Messages
27,300
Since you show an Ohio address, your site falls under the rules of the USA Privacy Act of 1974 and all subsequent amendments thereto. Unless you are a government site (state or federal), it may be illegal for you to use SSN as primary key. If your company has a legal department, that would be a good question to ask them. You might point them to start with US Code, Title 5, near section 552, and Title 18, near section 1030. But that isn't the only place those issues come up. Just two places that I KNOW reference the issue of sensitive personal data.

Yes, I know that insurance companies use your SSN all the time - but many of them cheat, while others get away with it because of the tax implications, particularly if they are subsidized by some form of government funding. THEY call SSN your "Taxpayer ID" - which oh so conveniently matches your SSN. Or they add a digit to it so that it isn't your SSN any more. But EVERYONE knows which digit to remove to GET your SSN. I get away with using SSN here because my site is military (US Navy). My primary DB relates to military personnel. I also run the host system for that database at security level C2 in order to have that info legally on line. Otherwise, I couldn't use it either.

As to whether you should continue to use SSN as a primary key, I cannot advise against it from a techie standpoint. SSN, because it is relatively short and is supposed to be unique, meets the requirements for a good primary key. If you take out the punctuation, CLng(SSN) can even fit into a long integer because the largest SSN currently possible is still less than 1 billion. Long integers can, of course, comfortably hold over 2 billion. So in that sense, SSN and a long integer autonumber are almost equal in their utility as keys.

Some purists suggest that primary keys must not also have meaning. I.e. because SSN has a meaning outside the context of your DB, it should not be a primary key. I happen to not be of that viewpoint. Sometimes it makes more sense to use an existing unique value as a key rather than synthesize another field with no particular meaning to act as a key.

Switching your tables to an autonumber field is certainly OK, but you would run into a massive update issue when you converted the records and relationships. Still, it COULD be done.

First, add the autonumber field to your table but DON'T let it be the primary key (yet).

Next, for every table that references SSN as a foreign key, add a long integer field to that table. Since here the key relation will be foreign, this new field is NOT an autonumber. At this point, the parent and child tables are still related through SSN.

Now write a query that copies the autonumber field value from the parent table to the corresponding new field in each child table. Since the existing SSN relationship is still intact, you can do this pretty easily.

Now make the autonumber field the new foreign key for the child table. Change all relationships with that table if they involved SSN. Immediately after all relationships are fixed for each table, DELETE the SSN field from the child table. Because at that point you have a non-key field that does not depend on the child table's primary key, which is one of the things that normalization rules say you shouldn't have.

Finally, change the primary key of the parent table from SSN to the autonumber field.

As to how we approach the issue of a change of primary key in a context of referential integrity, here is what I have found to be effective. I wrote a macro to run some code to do this. The code asks questions with input boxes to get the old and new keys for the "rename" operation. It then creates little append, update, and delete queries on the fly. The code opens these SQL queries as recordsets. Opening an action query as a recordset executes the query, of course.

First, open a SELECT query for the record to be changed. Copy all the data from the record. Make it a SnapShot record or something that clearly doesn't diddle with locks. Or, just close the recordset after you have copied what you wanted.

Next, open an APPEND query that copies everything else but the primary key to the same table. For the primary key, load the new value. Close the recordset.

Next, for each table containing foreign-key references, open an UPDATE query that changes the value in the primary key field for all records that match the old value of the primary key.

Finally, open a DELETE query on the parent table, deleting the record with the old value of the primary key.

Tedious, but if you break it up into parts, it isn't so bad.
 

vangogh228

Registered User.
Local time
Yesterday, 21:07
Joined
Apr 19, 2002
Messages
302
Doc_Man: I cannot tell you how much I appreciate the thorough reply. I don't quite understand all of it, though, like the part where you said:

"Now write a query that copies the autonumber field value from the parent table to the corresponding new field in each child table. Since the existing SSN relationship is still intact, you can do this pretty easily."

I'm not sure I know how to do that, but I did a practice, and wrote a select query that took the necessary fields from the main table and the field to be updated in the related. I then did a manual copy/paste from the new autonum field in the main table to the related field in the other table. Since that will be a one-time thing, I didn't feel too bad about using the query in this fashion.

I also see the value of keeping the relationship intact until this process is complete.... I do need it to be like that until I am done.

But, let me complicate things one step further. There are forms from the main data that contain subforms on the related. Do I have to make all new subforms? And, do I have to include the NEW key field on the forms somewhere (I feel like I have done that before and set them to not visible, but I am not sure).
 

vangogh228

Registered User.
Local time
Yesterday, 21:07
Joined
Apr 19, 2002
Messages
302
Doc_Man:

I tried to follow your instructions as well as I could, and I had a couple problems. The biggest one is that there are subtables related to the main data, and when I try to enter a new record in my main forms, choosing the SSN, it does not then enter the data into the new-related field. I am ending up with a column of blanks in the many-side of the relationship in the related field. Also, all my forms now are hosed. The subforms based on the subtables now ask me for the Relatedtbl.SSN, since I deleted SSN from the subtables after establishing the new relationships.

All my subforms are useless at this point. Help?

(Good thing I made a backup)
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 20:07
Joined
Feb 28, 2001
Messages
27,300
Shouldn't have to recreate ANY subforms.

Once you have mucked about in the tables, open your forms to where you have these sub-forms.

RightClick inside the sub-form, then call up Properties.

On the DATA tab, there are two properties to change:
LinkChildFields
LinkMasterFields

These should (currently) read SSN (or whatever you called it)

Change them BOTH to the name of the new prime key. If the names of the keys differ in the tables, you have the chance to enter the unique name for each in a different property, so the naming you chose really doesn't matter.

Now try the form in Form View. That should be all you need for the forms.

As to the "COPY" - this is an Update query. With the parent and child tables still containing SSN, you should have an existing relationship between them. If you don't, you should be aware that you can create a temporary relationship between two tables that is local to the current query. Just put the parent and child tables in the area above the query grid (use the Add Tables button to do it), then drag'n'drop the SSN field from the parent to the child. You can edit the properties of the relationship by rightclick on the line that joins the two fields, just like you could in the relationships window.

Let's stay the new field is called NPK (new prime key) in the parent and NFK (new foreign key) in the child. Basically, this is an update of the JOIN of the two tables, where you update Child.NFK to Parent.NPK

When you are done, the SQL MIGHT look like this (but I can never remember which way to do this, so do it in the design grid if you can...)

SQL: UPDATE Child INNER JOIN Parent ON Parent.SSN = Child.SSN SET Child.NFK = Parent.NPK ;

I can never remember the correct order of the two fields in the ON clause so DON'T BELIEVE ME. Play with it to see which is right. Also, if your child is a many-to-one relationship, this might turn out to be a RIGHT INNER JOIN (or perhaps a LEFTie, that's why I always play with it first...).

This is the step I was talking about earlier when I said to copy the new key from the parent to each child table.

You could ALSO have done it as a simpler update using DLookup except that the JOIN mechanism saves so much time and overhead. That might look like

UPDATE Child SET Child.NFK = DLookup( "[NPK]", "Parent", "[Parent]![SSN] = " & CStr([Child]![SSN]) )

The above assumes the SSN is numeric. Gets more complicated if it is not. But the JOIN method is far easier.

Sorry I didn't get back sooner. Getting ready for vacation and of course everyone wants everything done at once so that they won't miss me too much. Ha! I should live so long. The moment I get back, they'll flood me with things they forgot two minutes after I walked out of the door.
 
Last edited:

vangogh228

Registered User.
Local time
Yesterday, 21:07
Joined
Apr 19, 2002
Messages
302
Doc_Man:

Do you relaize that you are apologizing to me for not helping me fast enough?? Please... know that I am SO grateful for this help, regardless of when you take time from your schedule to give it. You are doing me a HUGE favor here, for which I will probably never be able to repay you.

I am going to take the weekend and practice this. Everything seemed to be going OK until I deleted the related field from the child table. Then none of my forms would work. So, I will practice this additional procedure and, if it works, I'll be a hero... because of your advice.

Thanks again!

Tom
 

Users who are viewing this thread

Top Bottom