Отказ от ответственности:, в то время как это возможно реализовать с помощью схемы базы данных, я настоятельно рекомендую вам использовать подход, описанный ниже в любом проекте реальной жизни.
Академически, чтобы сделать то, что вы хотите, вы должны перенести идентификационный ключ из Set с помощью внешних и внешних подмножеств. Схема будет выглядеть следующим образом:
use master;
go
if db_id('SampleDB') is not null
set noexec on;
go
create database SampleDB;
go
use SampleDB;
go
/*==============================================================*/
/* Table: Sets */
/*==============================================================*/
create table dbo.[Sets] (
[Id] int not null,
[Name] varchar(50) not null,
constraint [PK_Sets] primary key (Id)
)
go
/*==============================================================*/
/* Table: SubSets */
/*==============================================================*/
create table dbo.[SubSets] (
[SetId] int not null,
[SubsetId] int not null,
[Name] varchar(50) not null,
constraint [PK_SubSets] primary key (SetId, SubsetId)
)
go
alter table dbo.SubSets
add constraint FK_SubSets_Sets_SetId foreign key (SetId)
references dbo.Sets (Id)
go
/*==============================================================*/
/* Table: Items */
/*==============================================================*/
create table dbo.[Items] (
[Id] int not null,
[SetId] int not null,
[SubsetId] int null,
[Name] varchar(50) not null,
constraint [PK_Items] primary key (Id)
)
go
alter table dbo.Items
add constraint FK_Items_Sets_SetId foreign key (SetId)
references dbo.Sets (Id)
go
alter table dbo.Items
add constraint FK_Items_SubSets_SetIdSubsetId foreign key (SetId, SubsetId)
references dbo.SubSets (SetId, SubsetId)
go
set noexec off;
go
use master;
go
Как вы можете видеть, ПК на столе dbo.Subset несколько неточным. Разумеется, он служит своей цели, но его можно было бы упростить. Еще одна необычная вещь - колонка SubsetId в dbo.Таблица Items участвует в двух внешних ключах, которые указывают на разные таблицы.
Вы можете вставить некоторые данные в эту схему, и это будет прекрасно:
insert into dbo.Sets (Id, Name)
values
(1, 'Set 1'),
(2, 'Set 2');
go
insert into dbo.SubSets (SetId, SubsetId, Name)
values
(1, 1, 'Subset 1-1'),
(1, 2, 'Subset 1-2');
go
insert into dbo.Items (Id, SetId, SubsetId, Name)
values
(1, 1, 1, 'Banana'),
(2, 1, 1, 'Plate'),
(3, 1, 2, 'Charger'),
(4, 1, null, 'Toothpick'),
(5, 2, null, 'Cup');
И будет хит с нарушением ограничений FK при попытке добавить противоречивые данные, такие как это:
insert into dbo.Items (Id, SetId, SubsetId, Name)
values
(6, 2, 1, 'Fake t-shirt');
Подмножество 1 не относится к множеству 2, поэтому приведенная выше команда не будет выполнена.
теперь - почему вы никогда не должны использовать этот подход к дизайну, если не был вынужден сделать это в дуле пистолета:
- Не каждый бизнес ограничение может и должно быть реализовано на уровне схемы. Фактически, записывая его в хранимой процедуре, в большинстве случаев проще понять, поддерживать и работать;
- Он содержит редко используемые трюки, которые очень сбивают с толку, и неожиданно для большинства людей, даже опытных профессионалов базы данных. Все это , что соответствует стоимости обслуживания;
- И последнее, но не менее важное - запросы, которые будут корректно работать с таким видом схемы, как я могу это поставить, неудобно и трудно писать. Кроме того, вы, скорее всего, столкнетесь с множеством проблем, которые вы попытаетесь объединить эту схему с любым ORM. А может и нет; или, может быть, они будут проявляться только после того, как будут введены в производство и т. д.
Спасибо за отзыв о FK, я забыл включить его в вопрос. Чтобы быть ясным, я ищу решение для базы данных –