Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL - Supertype/Subtype design

I need to create the following database:

enter image description here

For semi-trucks I don't need extra subtypes, while for Car I need to have only those 3 subtypes and also for Sedan I need the four subtypes. For SELECTs I will use JOINs (normalized database) but I need to find an easy way to make INSERTs.

  • Vehicle table stores common information
  • Semi-truck stores specific information for semis
  • Car tables has specific fields for cars and a car_type field which is linked to the three subtypes
  • Van, Suv and Sedan (and other types if I would need them) should be in one table CAR_TYPE
  • However, for Sedan type I need to have additional subtypes which maybe should be contained in another table. These subtypes are not needed for Suvs and Vans (in real life suv, vans can have the same subtypes as sedans but not in my case).

I need this database to be created exactly as it is in the diagram.

So far, my first approach is to have the following tables:

  • Vehicle: veh_id, veh_type(Semi, car), ..., other_fields
  • Vehicle_semis: veh_id, ..., other_semis_fields
  • Vehicle_car: veh_id, car_type(Van, Suv, Sedan), other_car_specific_fields
  • Car_type: car_type_id, type
  • Sedan_type: sedan_type_id, type

My problem is that I'm not sure this would be the right approach, and I don't know exactly how to create relationships between the tables.

Any ideas?

Thank you!

UPDATE:

The following diagram is based on @Mike 's answer: enter image description here

like image 637
Cristian Avatar asked Jul 01 '13 13:07

Cristian


People also ask

What is the difference between supertype and subtype?

A supertype is a generic entity type that has a relationship with one or more subtypes. A subtype is a sub-grouping of the entities in an entity type that is meaningful to the organization and that shares common attributes or relationships distinct from other subgroups.

Can a subtype be a supertype?

A supertype can have one or more subtypes, and a subtype can have one or more supertypes. A supertype can be a subtype of some other supertype, and a subtype can be a supertype of some other subtype.

Can a Supertype have only 1 subtype?

In general, a supertype will have two or more subtypes. (Either that, or it will be possible for the supertype to have ``instances of its own,'' which aren't also instances of the subtype.) However, a subtype is (directly) a subtype of only one supertype.

Can subtypes have subtypes?

In fact, this diagram shows most of the sorts of relationships that seem to worry modelers, in particular the relationship between an entity class and its own supertype. Subtypes can themselves have subtypes. We need not restrict ourselves to two levels of subtyping.


1 Answers

Before I get started, I want to point out that "gas" describes either fuel or a kind of engine, not a kind of sedan. Think hard before you keep going down this path. (Semantics are more important in database design than most people think.)

What you want to do is fairly simple, but not necessarily easy. The important point in this kind of supertype/subtype design (also known as an exclusive arc) is to make it impossible to have rows about sedans referencing rows about semi-trucks, etc..

MySQL makes the code more verbose, because it doesn't enforce CHECK constraints. You're lucky; in your application, the CHECK constraints can be replaced by additional tables and foreign key constraints. Comments refer to the SQL above them.

create table vehicle_types (
  veh_type_code char(1) not null,
  veh_type_name varchar(10) not null,
  primary key (veh_type_code),
  unique (veh_type_name)
);

insert into vehicle_types values
('s', 'Semi-truck'), ('c', 'Car');

This is the kind of thing I might implement as a CHECK constraint on other platforms. You can do that when the meaning of the codes is obvious to users. I'd expect users to know or to figure out that 's' is for semis and 'c' is for cars, or that views/application code would hide the codes from users.

create table vehicles (
  veh_id integer not null,
  veh_type_code char(1) not null,
  other_columns char(1) default 'x',
  primary key (veh_id),
  unique (veh_id, veh_type_code),
  foreign key (veh_type_code) references vehicle_types (veh_type_code)
);

The UNIQUE constraint lets the pair of columns {veh_id, veh_type_code} be the target of a foreign key reference. That means a "car" row can't possibly reference a "semi" row, even by mistake.

insert into vehicles (veh_id, veh_type_code) values
(1, 's'), (2, 'c'), (3, 'c'), (4, 'c'), (5, 'c'), 
(6, 'c'), (7, 'c');

create table car_types (
  car_type char(3) not null,
  primary key (car_type)
);

insert into car_types values
('Van'), ('SUV'), ('Sed');

create table veh_type_is_car (
  veh_type_car char(1) not null,
  primary key (veh_type_car)
);

Something else I'd implement as a CHECK constraint on other platforms. (See below.)

insert into veh_type_is_car values ('c');

Only one row ever.

create table cars (
  veh_id integer not null,
  veh_type_code char(1) not null default 'c',
  car_type char(3) not null,
  other_columns char(1) not null default 'x',
  primary key (veh_id ),
  unique (veh_id, veh_type_code, car_type),
  foreign key (veh_id, veh_type_code) references vehicles (veh_id, veh_type_code),
  foreign key (car_type) references car_types (car_type),
  foreign key (veh_type_code) references veh_type_is_car (veh_type_car)
);

The default value for veh_type_code, along with the foreign key reference to veh_type_is_car, guarantees that this rows in this table can be only about cars, and can only reference vehicles that are cars. On other platforms, I'd just declare the column veh_type_code as veh_type_code char(1) not null default 'c' check (veh_type_code = 'c').

insert into cars (veh_id, veh_type_code, car_type) values
(2, 'c', 'Van'), (3, 'c', 'SUV'), (4, 'c', 'Sed'),
(5, 'c', 'Sed'), (6, 'c', 'Sed'), (7, 'c', 'Sed');

create table sedan_types (
  sedan_type_code char(1) not null,
  primary key (sedan_type_code)
);

insert into sedan_types values
('g'), ('d'), ('h'), ('e');

create table sedans (
  veh_id integer not null,
  veh_type_code char(1) not null,
  car_type char(3) not null,
  sedan_type char(1) not null,
  other_columns char(1) not null default 'x',
  primary key (veh_id),
  foreign key (sedan_type) references sedan_types (sedan_type_code),
  foreign key (veh_id, veh_type_code, car_type) references cars (veh_id, veh_type_code, car_type)
);

insert into sedans (veh_id, veh_type_code, car_type, sedan_type) values 
(4, 'c', 'Sed', 'g'), (5, 'c', 'Sed', 'd'), (6, 'c', 'Sed', 'h'),
(7, 'c', 'Sed', 'e');

If you have to build additional tables that reference sedans, such as gas_sedans, diesel_sedans, etc., then you need to build one-row tables similar to "veh_type_is_car" and set foreign key references to them.

In production, I'd revoke permissions on the base tables, and either use

  • updatable views to do the inserts and updates, or
  • stored procedures to do the inserts and updates.
like image 61
Mike Sherrill 'Cat Recall' Avatar answered Oct 07 '22 13:10

Mike Sherrill 'Cat Recall'