雜亂無章的資料經過正規化(Normalization),
產生出不同資料對應的不同資料表(Table),
但是每個資料表(Table)彼此之間需要認得彼此,
才不會原始資料被拆分之後卻無法組回來。
分手只是一時的,只要電話號碼還在,隨時可以舊情復燃。
現實世界可以聯繫的號碼在資料庫世界被稱為Key,
一張表會使用 Primary Key 當作唯一識別碼,
然後使用Foreign Key聯繫另一張資料表。
來看下面這個例子,原始表格記錄了使用者帳號的一些訊以及發佈哪一張相片,可以看到這張原始表格的id欄位是個流水號,這意味著這個值不會重復並且可以使用這個值來區別出每一筆資料,我們要把這個值當為 Primary Key,告訴全世界如果要找這張資料表的資料,麻煩請認這一欄的資料。
接著進行正規化,將使用者跟照片拆開,分為使用者資料表與相片資料表,兩張表都給流水號來識別資料,也就是兩張表都有各自的Primary Key。
id (PK) | username | sex | marry | education | photo_url | photo_name |
---|---|---|---|---|---|---|
1 | iopl | F | Y | bachelor | www/img/1.jpg | ya |
2 | iopl | F | Y | bachelor | www/img/2.jpg | happy |
3 | negativea | M | N | bachelor | www/img/3.jpg | oh |
4 | yuhsuanl | F | N | bachelor | www/img/4.jpg | smile |
5 | iopl | F | Y | bachelor | www/img/5.jpg | bed |
6 | iopl | F | Y | bachelor | www/img/6.jpg | kuku |
id (PK) | username | sex | marry | education |
---|---|---|---|---|
1 | negativea | M | N | bachelor |
2 | yuhsuanl | F | N | bachelor |
3 | iopl | F | Y | bachelor |
id (PK) | photo_url | photo_name |
---|---|---|
1 | www/img/1.jpg | ya |
2 | www/img/2.jpg | happy |
3 | www/img/3.jpg | oh |
4 | www/img/4.jpg | smile |
5 | www/img/5.jpg | bed |
6 | www/img/6.jpg | kuku |
拆分完成之後,有一個問題,把兩個表格一起看,也不知道哪個使用者有哪張照片,
資料本來是在混一起的,分開之後就不認得了,這是因為缺少兩張表的關聯性,
我們必須指出這張照片屬於哪個使用者帳號,或是這個使用者帳號有哪幾張照片,
先想想使用者跟照片的關係會是怎樣,下面兩個選項明顯第一項才是對的
因此可以說使用者對照片是屬於一對多的關係,
而照片對使用者是多對一的關係。
照片資料表(多的那方)可以加上一個欄位來找出使用者資料表(一的那方)對應的資料,
這個欄位也就會是 Foreign Key,加上去之後來看相片資料表,
第一筆會找到使用者帳號的第三筆,第二筆一樣會找到使用者帳號的第三筆,
對應起來就跟原始資料一樣了!
id (PK) | username | sex | marry | education |
---|---|---|---|---|
1 | negativea | M | N | bachelor |
2 | yuhsuanl | F | N | bachelor |
3 | iopl | F | Y | bachelor |
id (PK) | photo_url | photo_name | user_id (FK) |
---|---|---|---|
1 | www/img/1.jpg | ya | 3 |
2 | www/img/2.jpg | happy | 3 |
3 | www/img/3.jpg | oh | 1 |
4 | www/img/4.jpg | smile | 2 |
5 | www/img/5.jpg | bed | 3 |
6 | www/img/6.jpg | kuku | 3 |
Key 就是讓你來處理 <單個表格> 或 <多個有關聯的表格> 的資料識別。
由於流水號當識別資料這個方法非常非常的常見,
許多資料庫都有提供自動建立流水號的功能,
PostgreSQL SERIAL 是一種偽型別,
使用它宣告將獲得自動遞增值的特殊能力 :)
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
sex CHAR(1),
marry CHAR(1),
education VARCHAR(50)
);
CREATE TABLE photos (
id SERIAL PRIMARY KEY,
photo_url VARCHAR(200),
photo_name VARCHAR(200),
user_id INTEGER REFERENCES users(id)
);
最後想再特別強調一點的是主鍵不能被更改這個特性,我們來思考一下除了流水號之外,還有哪些資料具備唯一值的特性?以下幾種資料看起來具備這個特質
不過再仔細思考一下,這些資料會不會變動?
第一個來看手機號碼,這個很簡單,因為常常會有人換手機,所以我們知道手機號碼雖然是唯一值,但是手機號碼是會異動的,因此這並不適合拿來當Primary Key。
第二個來看電子信箱,通常分為兩種,一種是私人所有的電子信箱如Gmail,雖然不像手機這麼常見變更,但是電子信箱仍然是會被更換的,所以不能被當為Primary Key,而另一種是員工剛入職所申請的公司信箱,如果公司強烈要求這個員工這輩子不論以何種身分入職或離職後又入職都必須使用一開始申請過的那個信箱的話,那麼看起來是具備Primary Key這個條件,但是這樣有點不通情理,例如曾經在這間公司當過工讀生取了一個很中二的信箱名稱,但是他哪天以CTO的身分被聘入,這個信箱就很尷尬了喔,你說他不會想換嗎?另外有一個狀況,如果公司改名了呢?公司被合併了呢?信箱有可能會全面性變更名稱,所以電子信箱不論是私人或公司制訂都不適合拿來當Primary Key。
第三個來看員工編號,這就要看員工編號的組成有沒有識別什麼東西?例如110T00001,代表110年被聘入,T代表TEST測試部,00001代表流水號第一人,但是如果這個員工被調單位了,這組員編就會失去對應的意思,就會陷入要不要更改的尷尬情境,再來還有一種狀況,如果這個員工如果離職後又入職,那麼公司會用曾經有過員工編號去聘任嗎?還是會用新的員工編號去聘任?建議也不要直接把員工編號當作Primary Key。
第四個來看身分證,這很符合唯一值也有許多人一輩子沒聽過身分證可以變更,但是其實身分證是可以變更的,另外外籍員工沒有國內身分證,你可能會拿居留證號去當身分證,但是居留證號隨時都有可能改變的,因此身分證也不適合當Primary Key。
以上幾種例子就是直覺上可以當Primary Key,但是想的更多一些就發現在未來可能會發生問題,這就是為什麼這麼流行流水號(ID)這個欄位來當作Primary Key了,因為他並不代表任何意義,沒有任何變更的理由,如果一開始沒有設計好,那麼未來就可能成為系統難以處理的歷史包袱。