Database 在数据库中将多个值字段拆分为行的理想方法?

Database 在数据库中将多个值字段拆分为行的理想方法?,database,split,field,database-normalization,Database,Split,Field,Database Normalization,我有一个歌曲数据库,由歌曲标题、艺术家、歌词作者等字段组成。有时一首歌可以有多个艺术家或多个抒情者 我从数据库规范化中了解到,一个字段应该只有一个值,我应该将它们拆分为多个表,如song Artister表、song lyrist表,song_id是连接它们的主键 song table song_id | title | date 1 abc | 2017 但有了这样的设置,我的整个歌曲表就好像脱节了。有没有更漂亮的方法来分割它们 但有了

我有一个歌曲数据库,由歌曲标题、艺术家、歌词作者等字段组成。有时一首歌可以有多个艺术家或多个抒情者

我从数据库规范化中了解到,一个字段应该只有一个值,我应该将它们拆分为多个表,如song Artister表、song lyrist表,song_id是连接它们的主键

song table

song_id   |   title   |   date
  1            abc    |   2017

但有了这样的设置,我的整个歌曲表就好像脱节了。有没有更漂亮的方法来分割它们

但有了这样的设置,我感觉我的整个歌曲表都变了 支离破碎的有没有更漂亮的方法来分割它们

漂亮是一个非常主观的术语

设置1

就传统的数据库关系模型而言,像这样的N:M关系的“更漂亮”设置应该是规范化的,例如:

SONG (id, title, date)
PERSON (id, name)
SONG_ARTIST (song, person)
SONG_LYRICIST (song, person)
例如:

SONG
 ID       |   title   |   date
  1       |    abc    |   2017

PERSON
 ID       |    name
  1       |    John
  2       |    Mary

SONG_ARTIST
 SONG     |   person
  1       |     1
  1       |     2

SONG_LYRICIST
 SONG     |   person
  1       |     1
这是N:M关系的传统设置,它减少了1)存储数据所需的大小,2)冗余风险,以及3)更容易确保引用完整性

1) 如果艺术家约翰写了很多歌曲,在你的设置中,你输入约翰的次数也一样多。该字段单元格是一个字符串字段。这实际上取决于字段的长度,但通常字符串字段比整数字段需要更多的磁盘字节,因此重复文本字段通常比重复整数字段需要更多的磁盘空间

2) 冗余的风险之一与数据输入有关。如果您必须多次输入字符串,那么在某个时候您可能会拼写错误,从而创建一个“新”艺术家。另一个风险与数据维护有关。比如说,你发现你打错了一个艺术家的名字。这位艺术家写了10首歌,他的名字在你的数据库中出现了10次。你将不得不改变它10次,在大多数情况下,这项工作将需要手动完成(更多的时间和风险)

使用传统的关系设置,您只需键入艺术家的姓名一次。如果你拼写错误,它将被拼写错误的地方,但如果你改变它将自动改变为所有人

3) 僵化的结构有其困难,但一个人和他/她的歌曲之间的关系不容易被解读。它可能输入错误,但毫无疑问是哪首歌是哪位艺术家写的。该系统甚至能够区分两位同名艺术家。有鉴于此,您可以应用规则来确保引用的完整性(例如“在SONG_Artister中,当我将某个特定的人从表中删除时,删除该人的任何引用”)

即使你说你可以接受名字的改变,我还是强烈建议你把这些人放在他们自己的桌子上,在把他们和歌曲联系起来时引用他们

设置1.1

从上面的示例中,如果您想添加有关波段/组(或任何其他信息)的信息,则首先需要分析此实体与数据库中其他每个实体之间的关系

假设表格带区的初始基本定义如下:

BAND
 ID       |   title 
  1       |  TheBand
让我们从最简单的部分开始:

  • 歌。一首歌曲属于一个乐队,但一个乐队可能有许多歌曲(1:N)
要将乐队与其歌曲(1:N)关联起来,我们只需要将乐队id作为外键添加到歌曲表中

SONG
 ID       |   title   |   date    |    band
  1       |    abc    |   2017    |      1
只有这样,您才能列出乐队中的所有歌曲

SELECT song.id, song.title FROM song, band 
WHERE song.band=band.id AND band.id = 1
而且,因为我们知道每首歌的音乐家,我们也可以列出乐队中所有的音乐家或作词人

SELECT person.id, person.name, song.title 
FROM song, band, song_artist, person 
WHERE song.band=band.id AND song_artist.song=song.id 
AND person.id=song_artist.person AND band.id = 1
您可以决定这是您的应用程序需要知道的全部:“谁曾经参与过X乐队的任何歌曲”

否则,你可能想考虑到乐队经常邀请其他音乐家演奏某首歌,但这些人并不是乐队的一部分。如果您认为您的应用程序需要能够区分哪些人只是在团队中协作,哪些人属于团队的核心,那么您需要定义人员和团队之间的直接关系

  • 人。一个人可能是多个波段的核心组件,一个波段可能有多个核心组件(N:M)
正如您所知,在关系模型中,N:M关系必须通过使用第三个表来实现,该表将乐队和作为核心组件的人员放在一起

另一个问题出现了,因为特定波段的核心组件不是静态的,可能会随时间而变化。您可以通过在表BAND_CORE_组件中添加开始日期和结束日期来解决此问题,因此您知道,对于乐队中的每个人,他/她是何时开始和何时结束的,您可以询问数据库问题,例如:“2012年1月X乐队的核心组件是谁?”

在这里,你知道玛丽从2010年初到2016年年中一直是乐队的核心成员。我们还知道约翰后来(2012年)加入了乐队,现在仍然是乐队的一员。我们还知道John作为作词人和muscian参与了乐队的歌曲abc,并将其作为一个核心组成部分(因为这首歌始于2017年,John目前仍然是一个核心组成部分)。在同一首歌中,Mary作为合作者参与,因为这首歌的日期是2017年,而到那时她还不是乐队的核心成员

设置2

也就是说,最流行和最新的关系数据库系统,如MySQL或PostgreSQL的最新版本,包含了一些新类型,可以帮助您以不同的方式处理N:M关系,并减少设置中所需的表数量

JSON类型(MySQL 5.7.8及更高版本、PostgreSQL 9.2及更高版本)可用于存储SONG表中的关系

SONG
 ID       |   title   |   date    |              artists
  1       |    abc    |   2017    |  {"lyrics": [1], "music": [1,2]}

PERSON
 ID       |    name
  1       |    John
  2       |    Mary
甚至:

SONG
 ID       |   title   |   date    |              artists
  1       |    abc    |   2017    |  {"lyrics": [1], "music": {"voice": [1], "guitar": [2]}}

PERSON
 ID       |    name
  1       |    John
  2       |    Mary
这与其他设置具有类似的优点(减少冗余并保持引用完整性,对磁盘使用情况不太确定),但看起来更容易阅读

It简介
SONG
 ID       |   title   |   date    |              artists
  1       |    abc    |   2017    |  {"lyrics": [1], "music": [1,2]}

PERSON
 ID       |    name
  1       |    John
  2       |    Mary
SONG
 ID       |   title   |   date    |              artists
  1       |    abc    |   2017    |  {"lyrics": [1], "music": {"voice": [1], "guitar": [2]}}

PERSON
 ID       |    name
  1       |    John
  2       |    Mary
SONG
 ID       |   title   |   date    |              artists
  1       |    abc    |   2017    |  {"lyrics": [1], "music": {"voice": [1], "guitar": [2]}}
  2       |    def    |   2016    |  {"lyrics": [1], "music": [{"person": 1, "instrument": "voice"}, {"person": 2, "instrument": "guitar"}]}