Here is the scenario: You have a Persons table with a one-to-many relationship with an Addresses table, where one of the Address rows is the “primary” Address.
Is it better in a normalized schema to
- Use a Persons.PrimaryAddressID to access the “primary” Address for a Person
or
- Use an Addresses.IsPrimary bit column to reference the “primary” Address for a Person via Addresses.PersonID
or
- Other
and why?
It depends on whether the person-to-address relationship is one-to-zero-plus or one-to-one-plus.
If a person is required to have a primary address, I would put it in the
Personstable itself (since it’s a required attribute).In the other hand, if a person can exist in your schema without an address, I would leave all addresses in the
Addressestable as equal and use an attribute of thePersonstable to select the primary (either NULL or a pointer to the relevantAddressesrow).If you store the primality of an address in the
Addressestable, what do you do when two addresses for Bob Smith both claim to be the primary? You could stop that with triggers but it’s far more efficient to design your schema properly.And, if two room-mates share the same address, but one lives there all the time and the other spends most of his time shacked up with his girlfriend, what happens then? If the primality is in the Addresses table, you won’t be able to share address rows between persons.
What I’m trying to get across is that you need to allocate your attributes to the right objects. A person’s primary address belongs to a person, not an address.
For maximum efficiency and flexibility, I would have the following schema:
You have the minor data integrity problem that
Persons.PrimaryAddressIdmay be a hanging pointer. You can’t make it a foreign key to one of the primary keys since you want it to allowNULL. That means you’ll have to cater for the possibility that it might point to a non-existentAddresses.Id.I would simply fix that as a before-delete trigger on
Addressesso that the relevantPersonsrows are updated (settingPrimaryAddressidto NULL).Or you could be tricky and have one address of “Unknown” in the
Addressestable so that every row inPersonshas at least one address (those whose primary address is unknown automatically get theirPrimaryAddressidset to the “Unknown” address row.Then you could make it a proper constrained relationship and simplify your SQL somewhat. Pragmatism often beats dogmatism in the real world 🙂