如何在具有三元关系的表上进行选择?

时间:2010-12-18 19:18:47

标签: sql database-design

我正在通过为库设计数据库来开展学习项目。图书馆提供书籍,视频和音频。我决定将它的乐趣归结为那些为三元关系做贡献的人。这使得Quentin Tarrantino更容易成为同一部电影中的导演,作家和演员,同时也是一些书籍的作者,所有人都没有冗余以及他们在创作作品时所扮演的角色。

我称这三个基本实体涉及贡献者,角色和作品。

我遇到了问题,因为即使是在列出书籍的简单案例中,我也不确定我应该做些什么。对于每个贡献者/角色对,我最终会得到一个单独的行吗?或者有没有办法让结果塔有一些“临时”列(例如作者,插画家,一本书的翻译)。

感觉使用这种三元关系将层次结构注入到我的数据库中,我想知道如何最好地处理这种情况(请不要消除三元关系)。

[尾声] 我的查询工作得很好。 Stefan,我确实有一个中间表,所以你(以及其他阅读本文)知道。看起来三元关系为应用程序员提供了数小时的乐趣。

4 个答案:

答案 0 :(得分:2)

您实际上不能拥有ad-hoc列,因为每个列中可能有不同的行数。例如。一本书可能有一位作者,三位插图画家,也没有翻译。

要获取图书的贡献者列表,您必须选择与其相关的所有角色贡献者对,可能首先按角色排序,以便更轻松地进行分组,然后按角色分组贡献者并在页面上显示。

要编辑图书的数据,您必须验证所需角色的贡献者是否存在(例如,至少有一位作者)。这可以部分地通过ON UPDATE和ON DELETE触发器来完成,这些触发器将不允许删除最后剩下的作者;插入时你需要别的东西。

此外,我还会使用一个“模板”表,列出每种工作(work_type, role_type, is_required)的可能角色。如果is_required为真,则角色必须存在于有效工作中,如果为false,则允许角色但是可选。仅允许在表格中明确列出给定work_type的角色(因此您没有用于音乐曲目的书籍或插图画家的作曲家)。

答案 1 :(得分:0)

正如@Stefan H所指出的那样,你还需要一个连接表。您通过使用贡献者表来减少冗余,但看起来您将很难将角色编码到它们之间的连接表中。您也希望抽象出角色,因此您的表应如下所示:

Contributor
    ContributorID PK
Role
    RoleID PK
Work
    WorkID PK
ContributorRoleInWork
    ContributorRoleInWorkID PK
    (
        ContributorID FK
        RoleID FK
        WorkID FK
    ) --These three form a unique alternate key as well

要回答您的实际问题,是的,您将为每个ContributorRoleInWork获得一行,但这就是您想要的。当您列出图书的信息时,您需要为每个参与者/角色组合返回一行。为了便于显示信息,您可以按贡献者或角色进行排序/分组,具体取决于您希望如何显示数据。

答案 2 :(得分:0)

要回答这个问题,是的,每个Contribute / Role最终会有一个单独的行,例如,如果 John Doe既是执行制片人又是电影导演Foo。

            WORK             CONTRIBUTOR           ROLE
            Foo              John Doe             Director
            Foo              John Doe             Executive Producer

所以你有四个表(每个实体和链接表一个):

          WORKS
          CONTRIBUTORS
          ROLES
          WORKS_CONTRIBUTORS

链接表的主键是三元组:

          WORKS_CONTRIBUTORS
          workid
          contributorid
          roleid

答案 3 :(得分:0)

我认为这可能是最简单的解决方案(尽管不是最佳解决方案):

books           roles       people

ID              Role         ID
Name            BookID       Name
[other info]    PersonID     [Other info]

这样一来,如果你想知道给定书中的所有贡献者和他们的角色你可以使用隐式连接和

SELECT * FROM people,roles WHERE roles.BookID = [your book id] AND people.ID = roles.PersonID

同样,要获得某个人的所有贡献,你可以

SELECT * FROM books, roles WHERE roles.PersonID = [your person id] AND books.ID = roles.BookID

相反,如果你只想获得由某人执导的电影:

SELECT * FROM books, roles WHERE roles.PersonID = [your person id] AND roles.Role = "director" AND books.ID = roles.BookID

有更好的方法来编写这些查询:获取SQL方言的参考手册并查找JOIN。