Database 在数据库中将多个值字段拆分为行的理想方法?
我有一个歌曲数据库,由歌曲标题、艺术家、歌词作者等字段组成。有时一首歌可以有多个艺术家或多个抒情者 我从数据库规范化中了解到,一个字段应该只有一个值,我应该将它们拆分为多个表,如song Artister表、song lyrist表,song_id是连接它们的主键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 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)
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)
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"}]}