views:

53

answers:

3

Assume I have the following tables and relationships:

Person
- Id (PK)
- Name

A Person can have 0 or more pets:

Pet
- Id (PK)
- PersonId (FK)
- Name

A person can have 0 or more attributes (e.g. age, height, weight):

PersonAttribute
_ Id (PK)
- PersonId (FK)
- Name
- Value

PROBLEM: I need to represent pet attributes, too. As it turns out, these pet attributes are, in most cases, identical to the attributes of a person (e.g. a pet can have an age, height, and weight too). How do I represent pet attributes?

  1. Do I create a PetAttribute table?

    PetAttribute

    • Id (PK)
    • PetId (FK)
    • Name
    • Value
  2. Do I change PersonAttribute to GenericAttribute and have 2 foreign keys in it - one connecting to Person, the other connecting to Pet?

    GenericAttribute

    • Id (PK)
    • PersonId (FK)
    • PetId (FK)
    • Name
    • Value

    NOTE: if PersonId is set, then PetId is not set. If PetId is set, PersonId is not set.

  3. Do something else?

+1  A: 

You could do 1. but as your attributes are not fixed, they are just name value pairs this seems like a lot of duplication.

2 seems like a bad idea, as it is awkward to enforce the integrity with this sort of set up.

for 3, could you have a link table in the middle for an attribute group, which contains the id of the group and the ids of the individual GenericAttributes, then you have the AttributeGroupId as a property of the person and of the pet?

Table AttributeGroup
- Id (PK)
- GenericAttributeId  (PK,FK)

Table GenericAttribute
- Id (PK)
- Name
- Value

Person
- Id (PK)
- Name
- AttributeGroupId

Pet
- Id (PK)
- Name
- AttributeGroupId

so then the AttributeGroupId identifies a collection of GenericAttribute instances which are associated with the Pet or the Person. This also means that if you need to attribute something else in the future you just need to add the AttributeGroupId to that thing.

EDIT:

You really need to consider why you are doing this though. Are your attributes really dynamic, as this is the only reason I can think of that you would want this model? ie are your users defining the attributes in the application, can they add any attribute they want to a Person or a Pet? If not, if the application is in control of the attributes then you should consider Brock's advice. If the users are entering the attributes and their values themselves then you may need a model like this but it makes your queries much more complicated. If you can avoid it then its probably right to do so. I gave this as an example of a solution to your question, I can't suggest that it is a good idea without knowing more about your specific use case.

EDIT2:

As you have a fixed set of attributes that both a Pet and a Person can have you could have:

Attributes
- Id (PK)
- Attribute1
- Attribute2
...
- AttributeN

Person
- Id (PK)
- Name
- AttributesId (FK)

Pet
- Id (PK)
- Name
- AttributesId (FK)

Which avoids the duplication in all of the attributes if they are numerous and allows fairly simple querying, integrity checking, and strong typing of the data.

Sam Holder
+3  A: 

Actually, you should delete the PersonAttribute table and just add the columns (age, height, weight, etc.) to the Person table.

Add similar columns to the Pet table. This avoids a common beginner mistake called an "Entity Attribute Value Table". See "Five Simple Database Design Errors You Should Avoid", for example.

The only time you should put an "attribute", like weight, in a separate table is when the owner can have more than one of that exact attribute. Then the table should be specific, "WeightHistory", if it's a list of weights over time, etc.

Brock Adams
This is good advice. You need to consider why you need the attributes to be stored in a generic way. Are they really dynamic? updated my answer with some things you should consider.
Sam Holder
@BrockAdams: But what if the attributes of a Person vary from record to record? For example, say that for some Person, we store weight but not for all. This would result in records with a lot of empty columns. Isn't that a sign that the DB wasn't designed well?
StackOverflowNewbie
@StackOverflowNewbie, not necessarily. if the properties are fixed but might be empty, then so be it. This is a better solution than supporting dynamic properties (with all the problems that entails) when all you really need to support is nulls in some columns. How many properties are you going to have, and more importantly are they fixed? This should be what dictates your design IMHO.
Sam Holder
@SamHolder: I'm actually trying to model HTML form fields. Some of the fields ("Field" table) have a list of values ("FieldValueList" table), like radio or select. A "Field" can have 0 or more HTML attributes ("FieldAttribute" table). I later realized that "FieldValueList" also could have the same attributes as "Field."So, yes, I do have a fixed list of attributes (they're whatever the HTML spec says they are).Do I just add columns to my "Field" and "FieldValueList" tables for each of the HTML attributes?
StackOverflowNewbie
Are you going to want to query on those attributes, enforce integrity checks or have them strongly typed (ie not just string values), or just get them to list? If you are going to want to query (or enforce integrity checks etc) then I think i would go for the columns approach as that stuff will be so much easier. If you are only ever going to list the values then you could have the grouping table ...continued
Sam Holder
You could have a hybrid where the fixed attributes were all in a single table and the 'Field' table and 'FieldValuelist' table both have a FK into that attribute table, which avoids having the fields in both tables if they are numerous. I'll update my answer to include this.
Sam Holder
@SamHolder - I think I just need to store them, then later retrieve to create the string of attributes to include as part of the HTML tag (this is going to be used for a dynamically generated web form).Is there another way to model this? Maybe I don't need FieldValueList?
StackOverflowNewbie
@StackOverflowNewbie can't you just store the attribute string directly if that is all you need?
Sam Holder
@SamHolder - I need to be able to add/edit/delete individual attributes. Sure, I could save the entire attribute list in one column, then just parse it programmatically to do any operations on it -- but that won't be a good idea, right?
StackOverflowNewbie
@StackOverflowNewbie then my feeling is to go for the hybrid approach that I outlined in the second edit to my question, but you might want to wait and see if anyone else has any thoughts on the matter...
Sam Holder
@SamHolder - thanks, your hybrid solution looks elegant.
StackOverflowNewbie
A: 

I think that as you model PetAttribute and PersonAttribute deeper, you are going to find that are specializations of a more generic feature perhaps called PersonOrPetAttribute.

If it were up to me, I'd simply keep the two tables separate, until the absence of a table for PersonOrPetAttribute started to make queries more difficult.

If you see it differenlty, then you should probably do a google search on "generalization specialization relational modeling". This will find several good articles for you on the subject of modeling the gen-spec pattern with tables. The articles will tell you more about how to do this than I'm going to put in this response.

Walter Mitty