10

我需要创建以下数据库:

在此处输入图像描述

对于半卡车,我不需要额外的子类型,而对于汽车,我只需要这 3 个子类型,对于轿车,我需要四个子类型。对于 SELECT,我将使用 JOIN(标准化数据库),但我需要找到一种简单的方法来制作 INSERT。

  • 车辆表存储常用信息
  • 半卡车存储半卡车的特定信息
  • 汽车表具有汽车的特定字段和链接到三个子类型的 car_type 字段
  • Van、Suv 和 Sedan(以及其他类型,如果我需要的话)应该在一个表中 CAR_TYPE
  • 但是,对于轿车类型,我需要有可能应该包含在另一个表中的其他子类型。Suv 和 Vans 不需要这些子类型(在现实生活中的 suv 中,货车可以具有与轿车相同的子类型,但在我的情况下不是)。

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

到目前为止,我的第一种方法是拥有下表:

  • 车辆: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,类型
  • Sedan_type:轿车类型ID,类型

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

有任何想法吗?

谢谢!

更新:

下图基于@Mike 的回答: 在此处输入图像描述

4

2 回答 2

9

在开始之前,我想指出,“gas”既描述了燃料,也描述了一种发动机,而不是一种轿车。在你继续走这条路之前,请三思而后行。(语义在数据库设计中比大多数人想象的更重要。)

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

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”的单行表并为其设置外键引用。

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

  • 用于插入和更新的可更新视图,或
  • 存储过程来执行插入和更新。
于 2013-07-01T15:17:13.590 回答
3

我向您推荐以下三个标签下的“信息”选项卡:

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

他们没有完全回答您提出的问题,但他们对整个主题有所了解。这个在 SQL 中模仿继承的主题,在 SO 和 DBA 领域中一遍又一遍地出现。

于 2013-07-01T15:39:00.460 回答