0

Let's say I'm building a website about cars. The car entity has a lot of enum-like attributes:

  • transmission (manual/automatic)
  • fuel (gasoline/diesel/bioethanol/electric)
  • body style (coupe/sedan/convertible/...)
  • air conditioning (none/simple/dual-zone)
  • exterior color (black/white/gray/blue/green/...)
  • interior color (black/white/gray/blue/green/...)
  • etc.

The list of these attributes is likely to change in the future. What is the optimal way to model them in the database? I can think of the following options but can't really decide:

  • use fields in the car table with enum values
    • hard to add more columns later, probably the fastest
  • use fields in the car table that are foreign keys referencing a lookup table
    • hard to add more colums later, somewhat slower
  • create separate tables for each of those attributes that store the possible values and another table to store the connection between the car and the attribute value
    • easy to add more possible values later, even slower, seems to be too complicated
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Botond Balázs
  • 2,512
  • 1
  • 24
  • 34
  • 1
    Google for EAV: Entity Attribute Value. (AKA Smith & Smith) – wildplasser Nov 16 '12 at 22:49
  • @wildplasser: thanks, that solves the problem in a pretty neat way. Maybe you should add an answer that I can vote up. – Botond Balázs Nov 16 '12 at 22:58
  • No, I wont. It is too trivial. – wildplasser Nov 16 '12 at 23:07
  • See my answer to http://stackoverflow.com/questions/695752/product-table-many-kinds-of-product-each-product-has-many-parameters/695860#695860 – Bill Karwin Nov 16 '12 at 23:28
  • Please note that *though @BillKarwin is an authorithy on database design*, he is also known for hating the EAV model. – wildplasser Nov 16 '12 at 23:34
  • See also: http://dba.stackexchange.com/questions/27057/model-with-variable-number-of-properties-of-different-types – Craig Ringer Nov 17 '12 at 00:01
  • @wildplasser, I'm just trying to save people from the grief they will experience if they try to use EAV without knowing its weaknesses. – Bill Karwin Nov 17 '12 at 01:09
  • @wildplasser In other words, he's sensible? ;-) Use of EAV in more than the odd corner case in a DB is, IMO, a sign that you're using the wrong DB, not using the features of your DB properly, or slipping into the inner-system anti-pattern. Opinions vary, of course. – Craig Ringer Nov 17 '12 at 06:38

6 Answers6

1

Idealy is to create a relational database. Each table from DB should be represented by a class, as in hibernate. You should make 2 tables for the car. One for the interior and one for the exterior of the car. If you want to add extra features, you just add more columns.

cristi
  • 361
  • 3
  • 9
  • 1
    As far as I know, adding more columns when the table is very large might cause serious performance problems. – Botond Balázs Nov 16 '12 at 22:56
  • 1
    @BotondBalázs wide tables with a large dataset are fine so long as you use your queries correctly and have the correct indexes. Joining many large tables can equally be a performance issue – cEz Nov 16 '12 at 23:00
  • @Cez: You're right, and those joins will occur much more frequently than adding columns. Looks like I'll go with the wide table approach. – Botond Balázs Nov 16 '12 at 23:05
1

Now here is a (very basic) EAV model:

DROP TABLE IF EXISTS example.zvalue CASCADE;
CREATE TABLE example.zvalue
        ( val_id SERIAL NOT NULL PRIMARY KEY
        , zvalue varchar NOT NULL
        , CONSTRAINT zval_alt UNIQUE (zvalue)
        );
GRANT SELECT ON TABLE example.zvalue TO PUBLIC;

DROP TABLE IF EXISTS example.tabcol CASCADE;
CREATE TABLE example.tabcol
        ( tabcol_id SERIAL NOT NULL PRIMARY KEY
        , tab_id BIGINT NOT NULL REFERENCES example.zname(nam_id)
        , col_id BIGINT NOT NULL REFERENCES example.zname(nam_id)
        , type_id varchar NOT NULL
        , CONSTRAINT tabcol_alt UNIQUE (tab_id,col_id)
        );
GRANT SELECT ON TABLE example.tabcol TO PUBLIC;

DROP TABLE IF EXISTS example.entattval CASCADE;
CREATE TABLE example.entattval
        ( ent_id BIGINT NOT NULL
        , tabcol_id BIGINT NOT NULL REFERENCES example.tabcol(tabcol_id)
        , val_id BIGINT NOT NULL REFERENCES example.zvalue(val_id)
        , PRIMARY KEY (ent_id, tabcol_id, val_id)
        );
GRANT SELECT ON TABLE example.entattval TO PUBLIC;

BTW: this is tailored to support system catalogs; you might need a few changes.

wildplasser
  • 43,142
  • 8
  • 66
  • 109
1

This is really a duplicate of this dba.SE post:

https://dba.stackexchange.com/questions/27057/model-with-variable-number-of-properties-of-different-types

Use hstore, json, xml, an EAV pattern, ... see my answer on that post.

Community
  • 1
  • 1
Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
0

Depending upon the number of queries and size of the databases you could either:

  1. Make wide tables
  2. Make an attibutes table and a car_attributes table where: cars -> car_attributes -> attributes

#1 will make faster, easier queries due to less joins, but #2 is more flexible

cEz
  • 4,932
  • 1
  • 25
  • 38
0

It is up to the admin UI you need to support:

  • If there is an interface to manage for example the types of a transmission you should store this in a separate entity. (your option 3)
  • If there is no such interface the best would be to store in like enumerable type values. When you need another one(for example 'semi-automatic' for the transmission) you will add this only in the DB schema, as a matter of fact this will be the easiest to support and fastest to execute
Plamen Nikolov
  • 2,643
  • 1
  • 13
  • 24
0

I would create create table CarAttributes with column AttributeID,CarID,PropertyName,PropertyValue. When reslut set is returned we save it in IDictionary. It will allow you to add as many rows as you need without adding new columns.