当表中的每一列都是外键时,它是好还是过度?

Dav*_*ave 3 sql primary-key foreign-key-relationship

我正在构建一个可能的车辆数据库,其中每个条目都有一个Make,Model,Year和Engine.

我把它分成了制表(福特,雪佛兰,宝马等)和模型(Impala,Camaro,F-150等)和年(1920,...... 2012)和发动机(327,350等).

由于我现在每个Make,Model,Year和Engine都有一个表,并且每个表都有唯一的主键,因此主"MakesModelsAndYears"表中的每一行都只由四个外键组成.

这是否过度,或者真正存储的效率高于我创建独特索引的一个大表?我对"一个大桌子"方法的关注是像1970年这样的年代会重复多次(1970年雪佛兰Impala,1969年雪佛兰Camaro等),因为它有模型甚至引擎.

谢谢你的指导!

在此输入图像描述

跟进:

对于那些追随者,我将反馈结合到答案中并得出了这个模式.图像没有详细显示FK,但它们实际上是答案所暗示的:

在此输入图像描述

ype*_*eᵀᴹ 5

如果表格符合您的模型,则根本不存在具有2,3,4或更多外键的表,并且主键是这些FK的组合的问题.

我在这个设计中看到的唯一问题是它允许"BMW Escort"或"Ford Z4".也许您可以将设计更改为:

Makes
-----
Make PK


Models
------
Make  PK, FK to Makes
Model PK


MakesModelsAndYears
-------------------
Year       PK, FK1 to Years
Make       PK, FK2 to Model
Model      PK, FK2
EngineSize PK, FK3 to Engines
Run Code Online (Sandbox Code Playgroud)


Mik*_*ll' 5

雪佛兰不生产野马。福特在 1960 年没有制造野马。你的结构会允许很多废话。

问题不在于每一列都是外键;这没有什么问题。问题是外键是错误的。

我将其分为品牌(福特、雪佛兰、宝马等)和型号(Impala、Camaro、F-150 等)和年份(1920、... 2012)和发动机(327、350 等)的表格。

这就是为什么他们错了。当您规范化关系时,您关系开始,确定候选键,并计算出函数依赖关系。仅仅为每一列制作单列“查找”表并不是规范化,它不会以所需的方式约束您的数据。(在这种特殊情况下,约束是缺失的部分,而不是规范化到 5NF。)

Make       Model   Yr    Engine
--
Ford       F-150   2012  3.7L V6
Ford       F-150   2012  3.5L V6 EcoBoost
Ford       F-150   2012  5.0L V8
Ford       F-150   2012  6.2L V8
Ford       F-150   2011  3.7L V6
Ford       F-150   2011  3.5L V6 EcoBoost
Ford       F-150   2011  5.0L V8
Ford       F-150   2011  6.2L V8
Chevrolet  Camaro  2012  3.6L V6
Chevrolet  Camaro  2011  3.6L V6
Chevrolet  Camaro  2011  6.2L V8
Chevrolet  Camaro  1980  229ci V6
Chevrolet  Camaro  1980  267ci V8
Chevrolet  Camaro  1980  305ci V8
Cadillac   CTS     2004  3.6L V6
Vauxhall   Astra   1979  1.3L
Vauxhall   Astra   1979  1.6L
Vauxhall   Astra   1979  1.8L
Opel       Astra   1979  1.5L
Opel       Astra   1979  2.0L
Run Code Online (Sandbox Code Playgroud)

应该清楚,唯一的候选键是 {Make, Model, Yr, Engine}。所以这个表都是key,没有非主属性。

要将“查找”表添加为数据约束,仅仅说在第一列中您必须从 {Ford、Chevrolet、Cadillac、Vauxhall、Opel} 中进行选择并在第二列中您必须从 { 中进行选择是不够的F-150、Camaro、CTS、Astra}。品牌和型号的正确“查找”表包括品牌和型号;您可以选择 {福特 F-150、雪佛兰 Camaro、凯迪拉克 CTS、沃克斯豪尔 Astra、欧宝 Astra}。(在这种情况下,它更进一步。请参阅下面的表 model_years。)

create table makes (
  make varchar(25) primary key
);

insert into makes values
('Ford'),
('Chevrolet'),
('Cadillac'),
('Vauxhall'),
('Opel');

create table models (
  make varchar(25) not null references makes (make),
  model varchar(25) not null,
  primary key (make, model)
);

insert into models values 
('Ford', 'F-150'),
('Chevrolet', 'Camaro'),
('Cadillac', 'CTS'),
('Vauxhall', 'Astra'),
('Opel', 'Astra');

create table model_years (
  make varchar(25) not null,
  model varchar(25) not null,
  year integer not null check (year between 1900 and 2050),
  primary key (make, model, year),
  foreign key (make, model) references models (make, model)
);

insert into model_years values
('Ford', 'F-150', 2012),
('Ford', 'F-150', 2011),
('Chevrolet', 'Camaro', 2012),
('Chevrolet', 'Camaro', 2011),
('Chevrolet', 'Camaro', 1980),
('Cadillac', 'CTS', 2004),
('Vauxhall', 'Astra', 1979),
('Opel', 'Astra', 1979);

create table model_year_engines (
  make varchar(25) not null,
  model varchar(25) not null,
  year integer not null,
  engine varchar(25) not null,
  primary key (make, model, year, engine),
  foreign key (make, model, year) references model_years (make, model, year)
);

insert into model_year_engines values
('Ford', 'F-150', 2012, '3.7L V6'),
('Ford', 'F-150', 2012, '3.5L V6 EcoBoost'),
('Ford', 'F-150', 2012, '5.0L V8'),
('Ford', 'F-150', 2012, '6.2L V8'),
('Ford', 'F-150', 2011, '3.7L V6'),
('Ford', 'F-150', 2011, '3.5L V6 EcoBoost'),
('Ford', 'F-150', 2011, '5.0L V8'),
('Ford', 'F-150', 2011, '6.2L V8'),
('Chevrolet', 'Camaro', 2012, '3.6L V6'),
('Chevrolet', 'Camaro', 2011, '3.6L V6'),
('Chevrolet', 'Camaro', 2011, '6.2L V8'),
('Chevrolet', 'Camaro', 1980, '229ci V6'),
('Chevrolet', 'Camaro', 1980, '267ci V8'),
('Chevrolet', 'Camaro', 1980, '305ci V8'),
('Cadillac', 'CTS', 2004, '3.6L V6'),
('Vauxhall', 'Astra', 1979, '1.3L'),
('Vauxhall', 'Astra', 1979, '1.6L'),
('Vauxhall', 'Astra', 1979, '1.8L'),
('Opel', 'Astra', 1979, '1.5L'),
('Opel', 'Astra', 1979, '2.0L');
Run Code Online (Sandbox Code Playgroud)

除非它的行首先存在于 model_years 中,否则任何引擎都不能进入该表。没有年份可以进入 model_years,除非它的行首先存在于模型中。除非它的行首先存在于制造商中,否则任何行都不能进入模型。

您可以为ON UPDATE CASCADE在这样的模式中使用提供一个很好的案例。你也可以很好地说明不使用它。Oracle 不支持ON UPDATE CASCADE,这就是您看到 ID 号充斥 Oracle 表的原因之一,也是为什么您有时会看到人们说“主键值绝不能更改”的原因。

这些是实现已知需求所需的表类型。