views:

193

answers:

3

I am building a database system and having trouble with the design of one of my tables.

In this system there is a users table, an object table, an item table and cost table.

A unique record in the cost table is determine by the user, object, item and year. However, there can be multiple records that have the same year if the item is different.

The hierarchy goes user->object->item->year, multiple unique years per item, multiple unique items per object, multiple unique objects per user, multiple unique users.

What would be the best way to design the cost table?

I am thinking of including the userid, objectid and itemid as foreign keys and then using a composite key consisting of userid, objecid, itemid and costyear. I have heard that composite keys are bad design, but I am unsure how to structure this to get away from using a composite key. As you can tell my database building skills are a bit rusty.

Thanks!

P.S. If it matters, this is an interbase db.

+5  A: 

Use an internally generated key field (called surrogate keys), something like CostID, that the users will never see but will uniquely identify each entry in the Cost table (in SqlServer, fields like uniqueidentifier or IDENTITY would do the trick.)

Matthew Jones
+1: Surrogate Keys are far better than composite keys. Most of the time, they're the right way to do all keys.
S.Lott
I have seen this response before, but I am having trouble seeing how this will solve my problem. The record is uniquely identified by a combination of all 4 of the other columns. Could you give me an example of how I would query the database to retrieve a record based on the 4 inputs mentioned above?
kgrad
Exactly the same way you would if the fields represented the keys. SELECT * FROM Table WHERE User = @User, and so on.
Matthew Jones
@Matthew Jones I have to ensure that another record with the same attributes cannot be entered into my DB. How can I achieve this? With this solution people can enter multiple records with the same info and different unique generated id's. Do i have to use some sort of unique index? Is there a better way?
kgrad
@kgrad: in that case, define a unique constraint or unique index over those 4 rows, to ensure they're unique and no other row can be inserted with the same values
marc_s
+10  A: 

To avoid the composite key, you just define a surrogate key. This holds an artificial value, for instance an auto counter.

You still can (and should) define a unique constraint on these columns.

Btw: its not only recommended not to use composite keys, it's also recommendable to use surrogate keys. In all your tables.

Stefan Steinegger
+1 for composite key, and for the unique constraint!
marc_s
A: 

Try building your database with a composite key using exactly the columns you outlined, and see what happens. You may be pleasantly surprised. Making sure that there is no missing data in those four columns, and making sure that no two rows have the same value in all four columns will help protect the integrity of your data.

When you declare a composite primary key, the order of columns in your declaration won't affect the logical consequences of the dclaration. However the composite index that the DBMS builds for you will also have the columns in the same order, and the order of columns in a composite index does affect performance.

For queries that specify only one, two, or three of these columns, the index will be useless if the first column in the index is a column not specified in the query. If you know in advance how your queries are gonig to me, and which queries most need to run fast, this can help you declare the columns for the primary key in the right order. In rare circumstances creating two or three additional one column indexes can speed up some queries, at the cost of slowing down updates.

Walter Mitty