views:

2232

answers:

4

Hi, i'm have not much experience in table design. My goal is a product table(s), it must design to fix some requirement below:

  • Support many kind of products (TV, Phone, PC, ...). Each kind of product has different set of parameters like:

    • Phone will have Color, Size, Weight, OS...

    • PC will have CPU, HDD, RAM...

  • Set of parameters must be dynamic. You can add or edit any parameter you like.

I don't want make a table for each kind of product. So I need help to find a correct solution.

Thanks.

A: 

You can have a Product table and a separate ProductAdditionInfo table with 3 columns: product ID, additional info name, additional info value. If color is used by many but not all kinds of Products you could have it be a nullable column in the Product table, or just put it in ProductAdditionalInfo.

This approach is not a traditional technique for a relational database, but I have seen it used a lot in practice. It can be flexible and have good performance.

Steve Yegge calls this the Properties pattern and wrote a long post about using it.

RossFabricant
The Properties Pattern is just Entity-Attribute-Value by another name. It is used widely, but storing it in a relational database breaks rules of normalization.
Bill Karwin
To be honest, when I read the description of EAV in @Bills answer I did not quite understand what he was explaining. But when you said `3 columns: product ID, additional info name, additional info value` I understood the concept. And I have actually done this before, and ran into problems. However, I don't recall at the moment what those problems were.
John Isaacks
+43  A: 

You have at least these five options for modeling the type hierarchy you describe:

  • Single Table Inheritance: one table for all Product types, with enough columns to store all attributes of all types. This means a lot of columns, most of which are NULL on any given row.

  • Class Table Inheritance: one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type.

  • Concrete Table Inheritance: no table for common Products attributes. Instead, one table per product type, storing both common product attributes, and product-specific attributes.

  • Serialized LOB: One table for Products, storing attributes common to all product types. One extra column stores a BLOB of semi-structured data, in XML, YAML, JSON, or some other format. This BLOB allows you to store the attributes specific to each product type. You can use fancy Design Patterns to describe this, such as Facade and Memento. But regardless you have a blob of attributes that can't be easily queried within SQL; you have to fetch the whole blob back to the application and sort it out there.

  • Entity-Attribute-Value: One table for Products, and one table that pivots attributes to rows, instead of columns. EAV is not a valid design with respect to the relational paradigm, but many people use it anyway. This is the "Properties Pattern" mentioned by another answer. See other questions with the eav tag on StackOverflow for some of the pitfalls.


Additional thoughts about EAV: Although many people seem to favor EAV, I don't. It seems like the most flexible solution, and therefore the best. However, keep in mind the adage TANSTAAFL. Here are some of the disadvantages of EAV:

  • No way to make a column mandatory (equivalent of NOT NULL).
  • No way to use SQL data types to validate entries.
  • No way to ensure that attribute names are spelled consistently.
  • No way to put a foreign key on the values of any given attribute, e.g. for a lookup table.
  • Fetching results in a conventional tabular layout is complex and expensive, because to get attributes from multiple rows you need to do JOIN for each attribute.

The degree of flexibility EAV gives you requires sacrifices in other areas, probably making your code as complex (or worse) than it would have been to solve the original problem in a more conventional way.

And in most cases, it's an unnecessary to have that degree of flexibility. In the OP's question about product types, it's much simpler to create a table per product type for product-specific attributes, so you have some consistent structure enforced at least for entries of the same product type.

I'd use EAV only if every row must be permitted to potentially have a distinct set of attributes. When you have a finite set of product types, EAV is overkill. Class Table Inheritance would be my first choice.

Bill Karwin
A: 

Hi,

interesting post since i have exactly the same problem:

  • product database with +- 5 products with each a different (number of) paramaters
  • unpredictavle future products that must fit in this database/table design.

I agree with the downsides of AEV, buts how does i implement Class Table Inheritance ? i cannot find the trick to join a mastertable with a specific detail-table , depending on a attribute in the mastertable. (this is confom the definition of Class Table Inheritance off Bil Karwin)

Can please someone help me with this?

thanks

Bob
Hi Bob, welcome to StackOverflow. Note that unlike forum-based sites, we prefer new questions to be asked as, well, new questions, rather than additions to old questions. To ask a new question, click the Ask Question button up in the top right. Your text can include a hyperlink to this question, to help people understand the context of your question.
AakashM
A: 

If I use Class Table Inheritance meaning:

one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type. -Bill Karwin

Which I like the best of Bill Karwin's Suggestions.. I can kind of foresee one drawback, which I will try to explain how to keep from becoming a problem.

What contingency plan should I have in place when an attribute that is only common to 1 type, then becomes common to 2, then 3, etc?

For example: (this is just an example, not my real issue)

If we sell furniture, we might sell chairs, lamps, sofas, TVs, etc. The TV type might be the only type we carry that has a power consumption. So I would put the power_consumption attribute on the tv_type_table. But then we start to carry Home theater systems which also have a power_consumption property. OK its just one other product so I'll add this field to the stereo_type_table as well since that is probably easiest at this point. But over time as we start to carry more and more electronics, we realize that power_consumption is broad enough that it should be in the main_product_table. What should I do now?

Add the field to the main_product_table. Write a script to loop through the electronics and put the correct value from each type_table to the main_product_table. Then drop that column from each type_table.

Now If I was always using the same GetProductData class to interact with the database to pull the product info; then if any changes in code now need refactoring, they should be to that Class only.

John Isaacks