使用约束对多对一建模?

时间:2010-05-10 10:24:37

标签: sql-server database-design sql-server-2008 normalization referential-integrity

我正在尝试为电影分类创建数据库模型,其中每部电影可以从多个评级系统中的每一个(例如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 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

根据您的说法,ClassificationSystemIdMovieClassification的密钥的一部分,因为对于给定系统,给定系统只能有一个(或零)MovieClassification电影。

现在,有三种情况可以改变Classification表:

  1. 您向系统添加新分类。
  2. 您从系统中删除现有分类。
  3. 您可以更改分类的元数据(未在发布的架构中显示)。
  4. 在第一种情况下,一个例子是在现有的体裁系统中添加新的类型。你需要对属于新类型的电影进行重新分类是有意义的,因此模型成立。

    在第二种情况下,一个例子是从现有系统中删除一个类型。你需要对属于旧类型的电影进行重新分类仍然有意义,因此该模型仍然存在。

    在第三种情况下,您将更改例如类型的名称。已经归类为该类型的电影改变其类型名称是有道理的。该模型仍然存在。

    根据我的理解,正确的规范化是将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)
    );
    

答案 2 :(得分:0)

如果从分类表中删除分类系统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
)

但是你购买了另一个问题,即可以在其预期系统之外使用分类。

答案 3 :(得分:0)

同一分类系统中有多少不同的分类可归因于您设计的一部电影?

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

答案 4 :(得分:0)

  1. 在Classification(ClassificationId,ClassificationSystemId)
  2. 上添加唯一约束
  3. 从MovieClassification表
  4. 添加一个引用它的FK
  5. 在MovieClassification(MovieId,ClassificationSystemId)上添加唯一约束

答案 5 :(得分:0)

行。我曾希望我的问题会引发一些思考,但我的观点似乎已经错过了。

您的分类表必须是{movieID,classificationScheme classification},并且键为{movieID classificationScheme}。

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

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

答案 6 :(得分:0)

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

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

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