A: 

I also want to add one more thing, for the sake of simplicity, create views that expands address info to your tables or you may hate yourself for designing db this way.

Cem Kalyoncu
A: 

I'd consider a single AddressLink (name?) table with

LinkTypeID (Customer,Client,Contact,Facility) -- needs additional TypeID table
ID (CustomerID,ClientID...)
AddressID
AddressTypeID
AddressActive
LastUpdateUser
LastUpdateTime

Adding a new address link type means adding a new LinkTypeID w/o a new [TypeID]Addresses table, no queries need to be modified, and if you're looking for all uses of an Address (for deletes etc) there's only one place to look.

This is pretty similar to how we do it, anyway.

Oh, and we have an AddressLine3 in our Addresses (equivalent) table for some odd outlier situations.

DaveE
How do you enforce a foreign key constraint on ID with this structure? Or do you not bother?
APC
Insert/modify triggers validate that the ID column is valid relative to the LinkTypeID. FKs on the LinkTypeID, AddressID, and AddressTypeID columns, and "delete restrict" in place on the parent tables. I *think* that's done declaratively but could be triggers also. (MS SQL Server 2005)
DaveE
+1  A: 

A DBA where I used to work told me this gem, and it's worked great for us (the first two steps are the same as in your solution):

  1. Remove AddressLine1, AddressLine2, City, StateOrProvince, PostalCode from Customers, Contacts, Facilities and Clients.
  2. Create AddressTypes table with fields AddressTypeID, AddressTypeName, AddressTypeDescription, AddressTypeActive, LastUpdateUser, LastUpdateTime
  3. Create Addresses table with fields AddressID(PK), AddressTypeID(FK), AddressLine1, AddressLine2, City, StateOrProvince, PostalCode , LastUpdateUser, LastUpdateTime, CustomerID(FK), ClientID(FK), ContactID(FK), FacilityID(FK) 4.On the addresses table, set up a constraint so that only one of the CustomerID, ClientID, ContactID, or FacilityID foreign keys may be non-NULL at a time.

This way you've got all your addresses in one table, they can reference any record you need, your referential integrity is intact, and you don't have in intermediate table that you have to traverse.

The downside is that if you want to add addresses to a new class of object (e.g. an Employee table), you have to add a EmployeeID column to the Addresses table, but that's pretty easy.

Edward Robertson
What is the point of adding so many primary keys where the reverse can make the life easier and allow one to may relations where customers (just a sample) can have more than one address.
Cem Kalyoncu
The Customer *can* have more than one address. The Addresses table can have multiple rows that reference the same CustomerID. You just can't have the same address reference both a Customer and a Contact.
Edward Robertson
A: 

One additional thing that we have in our database that you might want to consider is to havea correspondence flag onthe address table with a trigger to enforce that only one address per person can bet as correspondence. We send out a lot of mail to people in our database and knowing which of the three addresses for that person is the one we need to use when sending mail is invaluable. It also makes its easier when querying to grab only one address per person to avoid getting multiple records per person for some reports.

HLGEM