Шевроле не делает Мустанг.Форд не производил Мустанг в 1960 году. Ваша структура позволит много глупостей.
Проблема не в том, что каждый столбец является внешним ключом;в этом нет ничего плохого.Проблема в том, что внешние ключи неверны.
Я разделил это на таблицы Makes (Ford, Chevrolet, BMW и т. Д.) И Models (Impala, Camaro, F-150 и т. Д.) И Years (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
Должно быть ясно, что единственным подходящим ключом является {Make, Model, Yr, Engine}.Таким образом, эта таблица является ключевой и не имеет непростых атрибутов.
Чтобы добавить таблицы «поиска» в качестве ограничений на данные, недостаточно сказать, что в первом столбце вы должны выбрать из {Ford, Chevrolet, Cadillac, Vauxhall, Opel}, а во втором столбце вы должны выбрать из {F-150, Camaro, CTS, Astra}.Правильная таблица соответствия для марки и модели включает как марку, так и модель;Вы выбираете из {Ford F-150, Chevrolet Camaro, Cadillac CTS, Vauxhall Astra, Opel 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');
Ни один движок не может войти в эту таблицу, если его строка не существует в model_years.Ни один год не может быть указан в model_years, если его строка не существует в моделях.И ни одна строка не может идти в моделях, если эта строка не существует в марках.
Можно привести хороший пример использования ON UPDATE CASCADE
в такой схеме.Вы также можете сделать хороший случай, чтобы не использовать его.Oracle не поддерживает ON UPDATE CASCADE
, что является одной из причин, по которым вы видите ID-номера, попадающие в таблицы Oracle, и почему иногда вы видите, что люди говорят: «Значения первичного ключа не должны никогда изменяться».
Это таблицы, которые вам нужны для реализации ваших известных требований.