2015-07-15 2 views
0

У меня есть модель, которая состоит в этих 3-х таблиц (в том числе):Обеспечение целостности отношений в модельном базе данных множеств и подмножеств

Item 
    PK id_item 
Set 
    PK id_set 
Subset 
    PK id_subset 
  • Каждый Item должен принадлежать к одному и только один Set (1. .N)
  • Вы можете определить ноль или более Subsets для каждого Set (0..n)
  • Каждый Item принадлежит к нулю или одному подмножеству (0..N)

Ive смоделировали базу данных, добавив следующую FK:

Item 
    PK id_item 
    FK id_set 
    FK id_subset 
Set 
    PK id_set 
Subset 
    PK id_subset 
    FK id_set 

Я не могу найти способ, чтобы запретить базу данных, чтобы принять Items, принадлежащие одному Set (А) и к Subset (В2), который принадлежит к другой Set (B).

Есть ли все-таки сделать это? Или это просто плохой дизайн/моделирование?

Это SQL Server 2008 базы данных

ответ

1

Во-первых, если элемент может принадлежать к подгруппе, необходимо добавить внешний ключ между таблицей Item и таблицы подмножества.

Во-вторых, добавьте ограничение проверки в таблицу элементов, которое будет гарантировать, что если subset_id не принадлежит в set_id, будет возникать исключение.

Чтобы сделать это, сначала вы создаете пользователя бросили вызов функции для проверки значения:

CREATE FUNCTION udf_CheckSubSet 
(
    @id_set int, 
    @id_subset int 
) 
RETURNS int 
AS 
BEGIN 
    IF @id_subset IS NULL OR EXISTS (
     SELECT 1 
     FROM Subset 
     WHERE id_subset = @id_subset 
     AND id_set = @id_set 
    ) 
    BEGIN 
     RETURN 1 
    END 
    -- logical else 
    RETURN 0 
END 

тогда вы создаете проверочное ограничение:

ALTER TABLE Item 
    ADD CONSTRAINT cc_Item_subset CHECK (dbo.udf_CheckSubSet(id_set, id_subset) = 1); 

Однако, я также предлагаю создать хранимую процедуры для вставки элемента и проверки внутри хранимой процедуры перед вставкой элемента.
Причина в том, что для обработки исключений гораздо дороже (с точки зрения производительности), а затем просто проверяйте ввод, прежде чем вставлять его в таблицу.

Возможно, вам интересно, почему вам даже требуется ограничение проверки, если вы уже справляетесь с проблемой с хранимой процедурой. Ответ на этот вопрос заключается в том, что ограничение проверки не позволяет вставлять обновление данных в таблицу, даже если кто-то пытается сделать это непосредственно из SSMS или просто написать инструкцию вставки или обновления.

+0

Спасибо за отзыв о FK, я забыл включить его в вопрос. Чтобы быть ясным, я ищу решение для базы данных –

1

Отказ от ответственности:, в то время как это возможно реализовать с помощью схемы базы данных, я настоятельно рекомендую вам использовать подход, описанный ниже в любом проекте реальной жизни.

Академически, чтобы сделать то, что вы хотите, вы должны перенести идентификационный ключ из 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. А может и нет; или, может быть, они будут проявляться только после того, как будут введены в производство и т. д.
+0

Спасибо за ваш ответ, это было действительно интересно, хотя ответ Жоара больше соответствует тому, что я искал. –

Смежные вопросы