优雅的规范化,无需添加字段,额外的表格。最好的关系

时间:2015-01-03 00:15:56

标签: database database-design database-normalization

我有两张桌子,我正在尝试规范化。问题是我不想创建一个包含新字段的副手表,尽管链接表可能有效。传达“任天堂”条目同时是出版商和开发商的最优雅方式是什么?我不希望“任天堂”被复制。我认为多对多的关系可以成为关键。

我想强调一点,我绝对希望保留开发人员和发布者表格。我不介意在2与新关系之间创建链接。

以下是我试图规范化的两个表:

enter image description here

以下是我尝试的解决方案(我不喜欢): enter image description here

4 个答案:

答案 0 :(得分:2)

你的两张桌子没有任何问题。

事实上,你所需要的只是

developer(name) -- company [name] is a developer
publisher(name) -- company [name] is a publisher

您的更改与规范化无关。规范化永远不会创建新的列名称。 '我不想要"任天堂"被复制'是误解。本身没有任何错误,价值出现在多个地方。请参阅sqlvogel&的答案。我自己here

但是:根据对某一行中某一行的含义,可能会有一个更好的设计来减少错误,因为这两个表'价值观可以被约束"即相互依赖。那个"冗余"有关。但它是关于约束的,并不涉及规范化。为了让我们能够解决这个问题,你必须根据世界情况确切地告诉我们每一行进入哪一行。

如果您不想重复字符串以实现(依赖)原因(占用空间或以更多连接为代价的操作速度),则添加名称ID的表和字符串(实际上是公司ID和名称),并按公司ID列和值替换旧名称列和值。但这不是规范化,为了依赖于实现的数据优化权衡,这会使您的模式复杂化。 (你应该演示这是必要的并且有效。)

接受的答案只是增加了很多冗余数据。就像你的问题增加了三个冗余表。这两个表已经说明哪些公司是开发者,哪些是发布者。其他表只是对两者的观点/查询!

如果你想要一个新的表#34; [id]用......和#34标识一个名为[name]的公司。那么这就是开发商和发行商作为超类型公司的子类型的情况。搜索数据库子类型。见this answer。然后,您将使用公司ID而不是名称来识别公司。您还可以使用公司ID作为表开发人员和发布者中的唯一列以及其他任何地方而不是developer_id和publisher_id来进一步简化(!)。

"冗余"不是关于多个地方出现的价值观。它是关于应用程序的多行说明相同的事情。当使用这样的设计时,存在两个基本问题:说某些事情涉及多行(而规范化版本只涉及一行);并且没有办法一次只说一件事(规范化可以帮助)。如果您对Nintendo做两个不同的独立声明,那么你需要两个表,并在每个表中提到任天堂。关于应用程序的重新行的陈述见this。 (并在我的其他答案中搜索表格"声明"或标准"。)规范化有帮助,因为它取代了行的状态为" ... AND的表格。 .."通过其他表格说明" ..."分别。请参阅thisthis。 (归一化通常被错误地认为涉及或包括避免多个类似的列,避免其值具有重复结构和/或用id替换字符串的列,但是尽管这些可能是好的设计思想,但它们不是规范化。)


在评论,聊天和其他答案中,您给出了这个起点:

enter image description here

这是最简单的设计。 (我假设游戏标题不是唯一的,所以你需要game_ids。)

-- game [game_id] with title [title] released on [release_date] is rated [rating]
game(game_id,title,release_date,rating)
game_developer(game_id,name) -- game [game_id] is developed by company [name]
game_publisher(game_id,name) -- game [game_id] is published by company [name]
game_platform(game_id,name) -- game [game_id] is on platform [name]

只有当您想要一个单独的公司列表以便公司可以存在而不开发或发布和/或可以拥有自己的数据时,您需要添加:

company(name,...) -- [name] identifies a company

只有当您需要开发人员和发布商的特定于角色的数据时才需要添加:

developer(name,...) -- developer [name] has ...
publisher(name,...) -- publisher [name] has ...

各种选项的相关外键都是直接的。

您的所有版本都不需要 _id。你的版本2& 3不会工作,因为他们不会说公司开发游戏或公司发布游戏的内容。你不需要角色,但是如果你拥有它们(Verison 2)那么你需要一张桌子"游戏[game_id]将公司[名称]作为[角色]" 。否则(Verision 3)您需要表格为#34; [game_id]由公司[名称]"开发。和#34;游戏[game_id]由公司[name]"发布。无论你与我的设计有什么不同,都要问自己为什么你有其他的结构,为什么你可以不用它而且(可能)为什么你会明确地想要它呢。

答案 1 :(得分:1)

我想你想要这样的东西:

Game_Company
ID    Name
 1    Retro Studios
 2    HAL Laboratories
 3    Nintendo
 ...

Company_Role
ID    Name
 1    Developer
 2    Publisher
 ...

Game_Company_Role
CompanyID    RoleID
        1         1
        2         1
        3         1
        3         2
 ...

获取具有“开发者”角色的所有公司的列表:

SELECT gc.name
FROM Game_Company gc JOIN Game_Company_Role gcr ON gcr.CompanyID=gc.ID
WHERE gcr.RoleID = 1

答案 2 :(得分:0)

这是解决问题的一种通用方法,可能会引起人们的兴趣。正如@Dour High Arch在他的解决方案中指出的那样,开发人员和发布者只是“派对”的角色。每个部分都有0,1或更多角色与给定的产品和角色可能重叠。这是好的和坏的。例如,产品可能由5位开发人员开发,但最多由1位发布者发布。 我选择将serial_id作为系统生成的PK引入,但这不是强制性的。您可以将3FK用作PK而不是用户serial_id。

请注意,将一方作为不同实体类型的概括并不总是好的,因为如果所有各方都不常见,则必须将一列或多列设置为非必需列,但这在实际应用中非常常见

公约:

name_PK =主键,

name_FK =外键

pic

答案 3 :(得分:0)

以下是评论提出的三个最终解决方案。您可以看到表格从顶部分解"未规范化"表

规则如下:

  • 1个游戏可以有1个或多个开发者,1个开发者可以有1个或多个游戏。
  • 1个游戏可以有1个或多个发布者,1个发布者可以有1个或多个游戏。
  • 1个游戏可以有1个或多个平台,1个平台可以有1个或多个游戏。

enter image description here

版本1

我离开了2"任天堂"红色的条目。根据研究和实施,这不是技术上冗余的数据。请参阅philipxy的回答。这看起来简单而优雅。 4个具有多对多关系的表。

enter image description here

这是关系图(4个表和3个链接表):

enter image description here

Verison 2

版本1"重复" "任天堂"但版本2有一个"公司"而是表。比较两个不同的版本。什么是正确的方法?

enter image description here

版本3

这是philipxy正在谈论的子类型。这个版本怎么样?

enter image description here