MySQL - 超类型/子类型设计

时间:2013-07-01 13:31:08

标签: mysql database-design

我需要创建以下数据库:

enter image description here

对于半卡车我不需要额外的亚型,而对于Car我只需要那3种亚型而且对于轿车我也需要四种亚型。 对于SELECT,我将使用JOIN(规范化数据库),但我需要找到一种简单的方法来进行INSERT。

  • 车辆表存储公共信息
  • 半卡车存储半成品的具体信息
  • 车牌表具有汽车的特定字段和car_type字段,该字段链接到三个子类型
  • 范,Suv和Sedan(以及其他类型,如果我需要它们)应该在一个表中CAR_TYPE
  • 但是,对于Sedan类型,我需要有其他子类型,这些子类型可能应该包含在另一个表中。 Suvs和Vans不需要这些子类型(在现实生活中,厢式货车可以与轿车具有相同的子类型但在我的情况下不是这样)。

我需要完全按照图中的方式创建此数据库。

到目前为止,我的第一种方法是使用以下表格:

  • 车辆:veh_id,veh_type(半,汽车),...,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,输入
  • Sedan_type:sedan_type_id,输入

我的问题是,我不确定这是不正确的方法,而且我也不确切知道如何在表格之间建立关系。

有什么想法吗?

谢谢!

更新

以下图表基于@Mike的回答: enter image description here

2 个答案:

答案 0 :(得分:7)

在我开始之前,我想指出“气体”描述燃料或某种发动机,而不是一种轿车。在继续沿着这条路走下去之前要认真思考。 (语义学在数据库设计中比大多数人想象的更重要。)

您想要做的事情相当简单,但不一定容易。这种超类型/子类型设计(也称为专用弧)的重要一点是,不能让关于轿车的行引用关于半卡车等的行。

MySQL使代码更加冗长,因为它不强制执行CHECK约束。你很幸运;在您的应用程序中,CHECK约束可以由其他表和外键约束替换。注释引用它们上面的SQL

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');

这可能是我在其他平台上作为CHECK约束实现的。当代码的含义对用户来说很明显时,您就可以这样做。我希望用户知道或者发现's'适用于半成品而'c'适用于汽车,或者视图/应用程序代码会隐藏用户的代码。

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)
);

UNIQUE约束允许列对{veh_id,veh_type_code}成为外键引用的目标。这意味着“汽车”行不可能引用“半”行,即使是错误的。

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)
);

我在其他平台上实现的CHECK约束。 (见下文。)

insert into veh_type_is_car values ('c');

只有一行。

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)
);

veh_type_code的默认值以及对veh_type_is_car的外键引用保证此表中的这些行只能是汽车,并且引用汽车的车辆。在其他平台上,我只是将栏目veh_type_code声明为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');

如果你必须构建引用轿车的其他表,例如gas_sedans,diesel_sedans等,那么你需要构建一个类似于“veh_type_is_car”的单行表,并为它们设置外键引用。

在生产中,我将撤销对基表的权限,并使用

  • 可更新的视图以执行插入和更新,或
  • 执行插入和更新的存储过程。

答案 1 :(得分:3)

我推荐您使用以下三个标签下的“信息”标签:

前两个描述了在设计关系数据库时处理类/子类(aka类型/子类型)情况的两种主要设计模式。第三种方法描述了一种使用单个主键的技术,该主键在超类表中分配并传播到子类表。

他们并没有完全回答你提出的问题,但他们对整个主题有所了解。这个模仿SQL中继承的主题在SO和DBA领域都反复出现。