但是通過這個設置,感覺就像我整個歌曲表已經脫節了 。有沒有更漂亮的方法來拆分它們?
漂亮是一個非常主觀的術語。
SETUP 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)剛性結構有其困難,但1人與他/她的歌曲之間的關係不容易解釋。它可能已經輸入錯誤,但毫無疑問,哪些歌曲寫了哪個藝術家。該系統甚至可以區分名爲相同的兩位藝術家。由於這一點,您可以應用規則來確保參照完整性(例如,「在SONG_ARTIST中刪除當我將其從表格PERSON中移除時,對特定人員的任何引用」)
即使您說可以接受名稱更改,我強烈建議你讓他們在自己的桌子上,並在與歌曲相關時引用他們。
設置1.1
從上面的例子,如果你想例如關於樂隊/組(或任何其他信息)添加信息,你需要做的第一件事就是分析這種實體之間的關係和數據庫中的其他實體。
假設表BAND的初始基本定義,如本:
BAND
ID | title
1 | TheBand
讓我們先從最簡單的部分:
- 歌曲。 1首歌曲屬於1個樂隊,但1個樂隊可能有許多歌曲(1:N)
要將樂隊與歌曲相關聯(1:N),我們只需要在表格中添加band_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的歌曲」。
否則,您可能想要考慮到樂隊經常邀請其他音樂家演奏某首歌曲,但這些樂隊並不是樂隊的一部分。如果您認爲您的應用程序需要區分誰正在樂隊中合作並且屬於樂隊核心,那麼您需要定義人與樂隊之間的直接關係。
- PERSON。 1人可能是許多頻段的核心部分,1頻段可能有許多核心部分(N:M)。
如您所知,關係模型中的N:M關係必須通過使用第三個表來實現,這個表將把樂隊和人員作爲核心組件進行組合。
另一個問題出現了,因爲特定頻段的核心組件不是靜態的,可能隨時間而變化。您可以通過在表BAND_CORE_COMPONENT中添加一個開始日期和結束日期來解決這個問題,因此您知道,對於樂隊中的每個人,他/她什麼時候開始以及他/她什麼時候結束,您可以詢問數據庫問題,例如: 「誰是2012年1月X組的核心組成部分?」。
BAND
ID | title
1 | TheBand
SONG
ID | title | date | band
1 | abc | 2017 | 1
PERSON
ID | name
1 | John
2 | Mary
SONG_ARTIST
SONG | person
1 | 1
1 | 2
SONG_LYRICIST
SONG | person
1 | 1
BAND_CORE_COMPONENTS
BAND | person | started | ended
1 | 2 | 2010-01-01 | 2016-06-01
1 | 1 | 2012-01-01 | *null*
在這裏,你知道,瑪麗曾是TheBand的核心組成部分,從2010年年初至2016年中期,我們也知道,約翰後來進入(2012年),仍然是TheBand的一部分。我們也知道約翰在TheBand的歌曲abc中作爲一個詞作者和muscian參與並且作爲核心組成部分(因爲這首歌曲從2017年開始,John目前仍然是核心組成部分)。 Mary在同一首歌曲中作爲合作者參與了歌曲,因爲這首歌曲可以追溯到2017年,當時她並不是TheBand的核心組成部分。
SETUP 2
話雖這麼說,最流行的和當前的關係數據庫系統,如MySQL或PostgreSQL在其最新版本中,加入一些新的類型,幫助你處理N:在A 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
這也有類似的優勢爲其它設置(減少冗餘,並保持引用完整性,不太確定磁盤使用情況),但似乎有點更容易閱讀。
它引入了一個新的風險來管理:您可以看到字段artists
允許您在其中存儲任何JSON,因此JSON結構可能在不同的行中有所不同,如果發生這種情況,那麼數據的結構完整性將會被打破,你的申請將不得不處理這個問題。
以下示例存儲相同的信息,但使用完全不同的JSON結構。
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"}]}
更多關於JSON類型在MySQL:Native JSON support in MYSQL 5.7 : what are the pros and cons of JSON data type in MYSQL?
這要看情況。你的「歌曲」表是讀或寫的?它是如何被查詢的? – Johnsyweb
你想把關於歌曲的所有信息放在一張表中?你可以用桌子很大,裏面有減少的數據嗎?你打算如何處理改變,比如歌曲標題改變或藝術家名字改變了? –
@ChetanRanpariya隨着目前的設置,藝術家名稱的變化可能已經很麻煩。 –