No.
I'd say there are certainly cases when single-field keys are inferior to compound keys, at least for the purpose of foreign keys. That is not to say you should not have a single-field surrogate key as well if you prefer, but I personally prefer the key that is most often used as the target of a foreign key to be called the primary key
I'll attempt to illustrate my point in the the following examples, in which:
brand
is car marque, eg Ford, Toyota etc
dealer
is a physical dealership, tied to a brand (eg a Ford dealership only selling Fords)
model
is the type of car eg Ford Focus, Ford Fiesta etc
stock
is the current forecourt car count for each dealership
If we create a single-field surrogate key for dealer
and model
as follows:
create table brand( brand_id integer primary key );
create table dealer( dealer_id integer primary key,
brand_id integer references brand )
create table model( model_id integer primary key,
brand_id integer references brand )
create table stock( model_id integer references model,
dealer_id integer references dealer,
quantity integer,
primary key(model_id, dealer_id) )
then it is possible to insert a row into stock
that links a Ford dealer
to a "Toyota" model. Adding brand_id references brand
to stock
only makes the problem worse. On the other hand if we keep the foreign key as part of the primary key as follows:
create table brand( brand_id integer primary key );
create table dealer( brand_id integer references brand,
dealer_id integer,
primary key(brand_id, dealer_id) )
create table model( brand_id integer references brand,
model_id integer,
primary key(brand_id, model_id) )
create table stock( brand_id integer,
model_id integer,
dealer_id integer,
quantity integer,
primary key(brand_id, model_id, dealer_id),
foreign key(brand_id, model_id) references model,
foreign key(brand_id, dealer_id) references dealer )
now the rule that "Ford" dealers can only stock "Ford" cars is enforced naturally by the model.
Note that in the 'composite keys' example, dealer_id
may or may not be unique, according to preference. It does not need to be unique (ie an alternate key), but very little is lost by making it so (perhaps a little storage space) and it can be very handy so that is the way I usually set it up, eg:
create table dealer( brand_id integer references brand,
dealer_id serial unique,
primary key(brand_id, dealer_id) )