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 Persons
table 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 Addresses
table as equal and use an attribute of the Persons
table to select the primary (either NULL or a pointer to the relevant Addresses
row).
If you store the primality of an address in the Addresses
table, 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:
Persons:
Id primary key
PrimaryAddressId
OtherStuff
Addresses:
Id primary key
OtherStuff
PersonAddresses:
Id primary key
PersonId foreign key on Persons(Id)
AddressId foreign key on Addresses(Id)
You have the minor data integrity problem that Persons.PrimaryAddressId
may be a hanging pointer. You can't make it a foreign key to one of the primary keys since you want it to allow NULL
. That means you'll have to cater for the possibility that it might point to a non-existent Addresses.Id
.
I would simply fix that as a before-delete trigger on Addresses
so that the relevant Persons
rows are updated (setting PrimaryAddressid
to NULL).
Or you could be tricky and have one address of "Unknown" in the Addresses
table so that every row in Persons
has at least one address (those whose primary address is unknown automatically get their PrimaryAddressid
set 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 :-)