Моделирование много-к-одному с ограничениями? - PullRequest
3 голосов
/ 10 мая 2010

Я пытаюсь создать модель базы данных для классификации фильмов, в которой каждый фильм может иметь одну классификацию из каждой из нескольких рейтинговых систем (например, BBFC, MPAA). Это текущий дизайн, со всеми подразумеваемыми PK и FK:

TABLE Movie 
( 
    MovieId INT -- PK
)

TABLE ClassificationSystem 
( 
    ClassificationSystemId TINYINT -- PK
)

TABLE Classification 
(
    ClassificationId INT,          -- PK
    ClassificationSystemId TINYINT -- FK
)

TABLE MovieClassification 
(
    MovieId INT,          -- composite PK, FK
    ClassificationId INT, -- composite PK, FK
    Advice NVARCHAR(250)  -- description of why the classification was given
)

Проблема заключается в таблице MovieClassification, ограничения которой допускают несколько классификаций из одной системы, в то время как в идеале она должна разрешать только одну или одну классификацию из данной системы.

Есть ли какой-нибудь разумный способ реструктурировать это так, чтобы фильм, имеющий ровно ноль или одну классификацию из любой данной системы, применялся из-за ограничений базы данных, учитывая следующие требования?

  • Не дублируйте информацию, которую можно искать (т. Е. Дублирование ClassificationSystemId в таблице MovieClassification не является хорошим решением, поскольку это может быть не синхронизировано со значением в таблице Classification)
  • Оставаться расширяемым для нескольких систем классификации (т.е. новая система классификации не требует каких-либо изменений в структуре таблицы)?

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

Ответы [ 7 ]

1 голос
/ 10 мая 2010

Вы можете применить это с проверочным ограничением, которое вызывает пользовательскую функцию. Например:

create function dbo.ClassificationSystemCheck()
returns int
as begin
    return (select max(cnt)
    from (
        select count(*) as cnt
        from MovieClassification mc
        left join Classification c
        on c.ClassificationId = mc.ClassificationId
        group by mc.MovieId, c.ClassificationSystemId
    ) qry)
end
go
alter table MovieClassification
add constraint chk_MovieClassification
check (dbo.ClassificationSystemCheck() <= 1)
go
alter table Classification
add constraint chk_Classification
check (dbo.ClassificationSystemCheck() <= 1)
go
insert into Classification select 1,1
insert into MovieClassification select 1,1
insert into MovieClassification select 1,1 -- Boom!

Это может быть неэффективно по мере роста количества классификаций. В качестве альтернативы вы можете исключить таблицу Classification и переместить ClassificationSystemId в таблицу MovieClassification.

0 голосов
/ 18 августа 2011

Честно говоря, я бы немного изменил модель данных.

create table #Movies (PK_moID int identity(1,1), moName varchar(50) primary key(PK_moID))
create table #ClassificationSystem (PK_csID int identity(1,1), csName varchar(50) primary key(PKcsID))
create table #Classification (PK_clID int identity(1,1), FK_csID int)
create table #MovieClassification (FK_moID int, FK_csID int, FK_clID int primary key (FK_moID, FK_csID))

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

0 голосов
/ 10 мая 2010

OK. Я надеялся, что мои вопросы заставят задуматься, но моя точка зрения, похоже, была упущена.

Ваша таблица классификации должна иметь вид {movieID ,ificationScheme классификация} с ключом {movieIDificationScheme}.

Он может ссылаться на фильм через {movieID}, а также может ссылаться на таблицу классификаций через {классификацииScheme классификация}.

Эта таблица классификаций перечисляет / перечисляет / называет все действительные классификации каждой схемы. Поскольку схема классификации существует и имеет смысл, с того момента, как она имеет хотя бы одну классификацию, может не возникнуть реальной необходимости в четвертой таблице, единственной целью которой является перечисление / наименование / перечисление всех соответствующих схем классификации. 1007 *

0 голосов
/ 10 мая 2010
  1. добавить уникальное ограничение на Classification (ClassificationId, ClassificationSystemId)
  2. добавить FK, ссылаясь на него из таблицы классификации фильмов
  3. добавить уникальное ограничение для MovieClassification (MovieId, ClassificationSystemId)
0 голосов
/ 10 мая 2010

Сколько различных классификаций одной и той же системы классификации можно отнести к одному отдельному фильму по вашему дизайну?

Соответствует ли это вашей предполагаемой концепции "классификации"?

0 голосов
/ 10 мая 2010

Что если вы удалите идентификатор системы классификации из таблицы классификации и сохраните его только в классификации фильмов?

TABLE Movie 
( 
    MovieId INT
)

TABLE ClassificationSystem 
( 
    ClassificationSystemId TINYINT
)

TABLE Classification 
(
    ClassificationId INT,
)

TABLE MovieClassification 
(
    MovieId INT,
    ClassificationId INT,
    ClassificationSystemId TINYINT,
    Advice NVARCHAR(250) -- description of why the classification was given
)

но вы покупаете еще одну проблему, которая заключается в том, что классификация может быть использована вне ее предполагаемой системы.

0 голосов
/ 10 мая 2010

Из того, что вы говорите, ClassificationSystemId является частью ключа для MovieClassification, поскольку может быть только один (или ноль) MovieClassification для данной системы для данного фильма.

Теперь есть три случая, когда таблица Classification может измениться:

  1. Вы добавляете новую классификацию в систему.
  2. Вы удаляете существующую классификацию из системы.
  3. Вы меняете метаданные для классификации (в опубликованной схеме они не отображаются).

В первом случае примером может быть добавление нового жанра к существующей системе жанров. Это имеет смысл, что вам нужно реклассифицировать фильмы, которые относятся к новому жанру, поэтому модель справедлива.

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

В третьем случае вы можете изменить, например, название жанра. Имеет смысл, что фильмы, уже классифицированные как этот жанр, меняют название своего жанра. Модель все еще держит.

Из того, что я могу понять, правильная нормализация - это поместить ClassificationSystemId в MovieClassification и сделать его частью ключа MovieClassification (и сделать ClassificationSystemId частью ключа для Classification строк в предоставленном схема):

-- Tables Movie, ClassificationSystem not included for brevity

CREATE TABLE Classification
(
  ClassificationId INT,
  ClassificationSystemId INT,
  PRIMARY KEY(ClassificationId, ClassificationSystemId),
  FOREIGN KEY(ClassificationSystemId) REFERENCES ClassificationSystem(ClassificationSystemId)
);

CREATE TABLE MovieClassification
(
  ClassificationId INT,
  ClassificationSystemId INT,
  MovieId INT,
  Advice NVARCHAR(MAX),
  PRIMARY KEY(ClassificationId, ClassificationSystemId, MovieId),
  FOREIGN KEY(ClassificationId, ClassificationSystemId) REFERENCES Classification(ClassificationId, ClassificationSystemId),
  FOREIGN KEY(MovieId) REFERENCES Movie(MovieId),
  UNIQUE(ClassificationSystemId, MovieId)
);
...