具有约束的多对一建模?

发布于 2024-08-31 13:15:53 字数 1022 浏览 6 评论 0原文

我正在尝试为电影分类创建一个数据库模型,其中每部电影都可以有来自多个评级系统(例如 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 表,其约束将允许来自同一系统的多个分类,而理想情况下它应该只允许来自同一系统的零个或一个分类给定的系统。

考虑到以下要求,是否有任何合理的方法可以对其进行重组,以便通过数据库约束强制执行具有任何给定系统的零或一个分类的电影?

  • 不要重复可以查找的信息(即在 MovieClassification 表中重复 ClassificationSystemId 并不是一个好的解决方案,因为这可能与 MovieClassification 表中的值不同步>分类表)
  • 保持可扩展到多个分类系统(即新的分类系统不需要对表结构进行任何更改)?

另请注意 Advice 列 - 电影到分类的每个映射都需要有一个文本描述,说明为什么为该电影赋予该分类。任何设计都需要支持这一点。

I'm attempting to create a database model for movie classifications, where each movie could have a single classification from each of one of multiple rating systems (e.g. BBFC, MPAA). This is the current design, with all implied PKs and FKs:

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
)

The problem is with the MovieClassification table whose constraints would allow multiple classifications from the same system, whereas it should ideally only permit either zero or one classifications from a given system.

Is there any reasonable way to restructure this so that a movie having exactly zero or one classifications from any given system is enforced by database constraints, given the following requirements?

  • Do not duplicate information that could be looked up (i.e. duplicating ClassificationSystemId in the MovieClassification table is not a good solution because this could get out of sync with the value in the Classification table)
  • Remain extensible to multiple classification systems (i.e. a new classification system does not require any changes to the table structure)?

Note also the Advice column - each mapping of a movie to a classification needs to have a textual description of why that classification was given to that movie. Any design would need to support this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

月竹挽风 2024-09-07 13:15:53

您可以使用调用用户定义函数的检查约束来强制执行此操作。例如:

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 表。

You can enforce that with a check constraint that calls a user defined function. For example:

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!

This can be inefficient as the number of classifications grows. Alternatively, you could eliminate the Classification table and move the ClassificationSystemId to the MovieClassification table.

土豪我们做朋友吧 2024-09-07 13:15:53

如果从分类表中删除分类系统id,只保留在电影分类上会怎么样?

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
)

但你会遇到另一个问题,即分类可以在其预期系统之外使用。

What if you remove the classification system id from the classification table and only keep it on the movie classification?

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
)

but you buy another problem, that a classification could be used ouside its intended system.

花海 2024-09-07 13:15:53

根据您的设计,同一分类系统中的一部电影可以有多少种不同的分类?

这符合您的“分类”概念吗?

How many distinct classifications of the same classification system can be attributed to one single movie under your design ?

Does that match your intended concept of "classification" ?

国产ˉ祖宗 2024-09-07 13:15:53

根据您的说法,ClassificationSystemIdMovieClassification 的键的一部分,因为只能有一个(或零个)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)
);

From what you're saying, ClassificationSystemId is part of the key for a MovieClassification, since there can be only one (or zero) MovieClassification for a given system for a given movie.

Now, there are three cases where the Classification table can change:

  1. You add a new classification to a system.
  2. You remove an existing classification from a system.
  3. You change metadata for a classification (none shown in your posted schema).

In the first case, an example would be adding a new genre to an existing system of genres. It makes sense that you need to reclassify movies which belong to the new genre, so the model holds.

In the second case, an example would be removing a genre from an existing system. It still makes sense that you need to reclassify movies which belonged to the old genre, so the model still holds.

In the third case, you would change for instance the name of a genre. It makes sense that movies already classified as that genre gets their genre name changed. The model still holds.

From what I can understand, the correct normalization is to put ClassificationSystemId in MovieClassification and make it part of the MovieClassification key (and make ClassificationSystemId part of the key for Classification rows in the provided schema):

-- 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)
);
安稳善良 2024-09-07 13:15:53
  1. 添加对分类的唯一约束 (ClassificationId,ClassificationSystemId)
  2. 添加从 MovieClassification 表引用它的 FK
  3. 添加对 MovieClassification 的唯一约束 (MovieId,ClassificationSystemId)
  1. add a unique constraint on Classification (ClassificationId,ClassificationSystemId)
  2. add a FK referring to it from MovieClassification table
  3. add a unique constraint on MovieClassification (MovieId,ClassificationSystemId)
好菇凉咱不稀罕他 2024-09-07 13:15:53

好的。我本来希望我的问题能引发一些思考,但我的观点似乎被忽视了。

您的分类表需要为{movieID,classificationSchemeclassification},键为{movieIDclassificationScheme}。

它可以通过{movieID}引用电影,并且可以通过{classificationScheme分类}引用分类表。

该分类表列出/枚举/命名每个方案的所有有效分类。由于分类方案仅存在且有意义,从它具有至少一个分类的那一刻起,可能并不真正需要第四个表,其唯一目的是列出/命名/枚举所有相关分类方案。

OK. I had hoped my questions would trigger some thinking, but my point seems to have been missed.

Your classification table needs to be {movieID, classificationScheme classification}, with key {movieID classificationScheme}.

It can reference Movie via {movieID}, and it can reference a classifications table via {classificationScheme classification}.

This classifications table lists/enumerates/names all the valid classifications of each scheme. Since a classification scheme only exists, and makes sense, from the moment it has at least one classification, there may not be a real need for a fourth table whose sole purpose it is to list/name/enumerate all the relevant classification schemes.

眼眸里的快感 2024-09-07 13:15:53

老实说,我只是稍微改变一下数据模型。

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))

现在,通过电影分类,您拥有电影和系统的复合 pk,因此每个系统只能获得一部电影的一个评级(即使您添加新系统)。您还可以创建从电影分类到分类表的关系以补充数据。

Honestly, i'd just change the data model around a little bit.

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))

now, with your movie classification you have a composite pk of the movie and the system, so you can only get one rating of a movie per system (even if you add new systems). you can also create a relationship from movie classification to the classificaiton table to enfore the data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文