[你阿罵也看得懂的軟體開發]關聯式資料庫

本系列文將會以最淺顯好懂的方式說明相關議題,已經了解的朋友或許也能從中知悉一些脈絡細節,希望這些文章能讓讀者們有所收穫。

Relational Database

--------------------------------------------------------------

資訊系統一定會有資料,資料動輒萬筆起跳,想像一下,現實世界裡你要怎麼擺放一萬顆螺絲釘,才能讓你在你要放入新的螺絲釘跟找到某顆螺絲釘的時候,都快速有效確實呢?關聯式資料庫就是個大概已經成熟了超過十年以上的解,剛好有同事問,來介紹一下簡單的例子吧。

以早年(?)網站教學書本最喜歡用的論壇為例好了,首先你會需要紀錄使用者的紀錄,在資料庫裡這樣的單位叫Table(表格),其中有一個很重要的欄位叫key,他將會作為table裡的每一筆資料的識別唯一用途:

使用者table
Key Name 密碼 建立日期 ...
1 人1 碼1 2018/10/08  
2 人2 碼2 2018/10/08  

論壇所以還要有文章table

文章table
Key Title 本文 建立日期 ...
1 文章1 本文1 2018/10/08  
2 文章2 本文2 2018/10/08  

而這時候怎麼知道哪篇文章的作者是誰?如果這個議題是1對1,也就是說一個作者只有一篇文章,一篇文章也只有一個作者,那麼下面兩種方式其實都可以(只需要使用其中一種),表示了使用者1是文章1的作者、使用者2是文章2的作者

 

使用者table
Key 文章Key Name 密碼 建立日期 ...
1 1 人1 碼1 2018/10/08  
2 2 人2 碼2 2018/10/08  
文章table
Key 使用者Key Title 本文 建立日期 ...
1 1 文章1 本文1 2018/10/08  
2 2 文章2 本文2 2018/10/08  

 

這其中,第二行的(文章key/使用者key),又被稱為外來鍵(foreign key),對應到其他table的key

BUT,你知我知獨眼龍也知道,文章跟作者的關係不是1對1,而是1對多,一個作者可以有多篇文章,但一篇文章只有一個作者,所以就只能把外來鍵加在文章那邊,表示了使用者1是文章1的作者、使用者2是文章2、3的作者

文章table
Key 使用者Key Title 本文 建立日期 ...
1 1 文章1 本文1 2018/10/08  
2 2 文章2 本文2 2018/10/08  
3 2 文章3 本文3 2018/10/08  

 

那麼如果要記錄每篇文章把哪些使用者看過呢?這是一個多對多的關係,一個使用者可以看過不只一篇文章,一篇文章也能夠被不只一個使用者看過,這時候就無法只使用兩張表紀錄,需要第三張表,第一篇文章被使用者2、3看過,第二篇文章被使用者1看過,第三篇文章被使用者2看過。

使用者_文章table
文章Key 使用者Key 建立日期 ...
1 2 2018/10/08  
2 1 2018/10/08  
3 2 2018/10/08  
1 3 2018/10/08  

以上例來說使用者Table跟文章Table其實有不只一種關聯(作者-文章,讀者-文章),能不能一起處理?或是再加一種關聯好了,現在還想要紀錄哪些使用者按過文章讚,如下所式

使用者_文章table
文章Key 使用者Key 種類 建立日期 ...
1 2 看過 2018/10/08  
2 1 看過 2018/10/08  
3 2 看過 2018/10/08  
1 3 按讚 2018/10/08  
1 2 按讚 2018/10/08  

這其中比較微妙的是,以上所看到都是共用的欄位,但當你一張表開始記了太多不同的資訊時候(學術用語叫不夠正規化),就會有些問題,比如上面的按讚如果改成打賞,而又需要紀錄打賞金額呢?你就會在一張表中出現大量空值欄位

使用者_文章table
文章Key 使用者Key 種類 金額 建立日期 ...
1 2 看過 x 2018/10/08  
2 1 看過 x 2018/10/08  
3 2 看過 x 2018/10/08  
1 3 打賞 50 2018/10/08  
1 2 打賞 40 2018/10/08  

 

另外有一個常見的設計,當你一張表太長的時候你可能會把同一個key的資料拆分,比如你今天使用者的資訊越記越多,當你有一個使用者會員卡(?)你可能就可以分開來,但是兩邊的key基本是保持1對1的關係

使用者table
Key Name 密碼 建立日期 ...(500行了,不想加在這了)
1 人1 碼1 2018/10/08  
2 人2 碼2 2018/10/08  
會員卡table
Key 使用者key 會員卡等級 會員卡日期
1 1 1 2018/10/08
2 2 1 2018/10/08

這裡有一種比較不好的情況是,當你覺得每次拿到會員卡還要去關聯使用者很麻煩,想把使用者的資料放到會員卡的時候

會員卡table
Key 使用者key 會員名稱 會員卡等級 會員卡日期
1 1 姓名1 1 2018/10/08
2 2 姓名2 1 2018/10/08

你會覺得這樣拿出來(查詢)的時候簡單很多,你只需要查會員卡這張表,但你有想過你這樣放進去(修改)的時候你就要修改兩處,如果你忘了修改兩處更可怕,兩邊的資料就不一致了。

 

最神秘的設計出現了,當某些時候想不開不想開新表時候就會出現

使用者阿哩阿砸table
Key 使用者key 對應種類 會員卡key 會員卡日期 文章key 打賞 ...
1 1 會員卡 1 2018/10/08 x x  
2 1 作者 x x 1 x  
3 2 會員卡 2 2018/10/08 x x  
4 2 打賞 x x 1 20  
5 1 打賞 x x 2 5  

看出上面記了什麼了嗎?1號使用者有一張會員卡1、1號使用者是文章1的作者、1號使用者打賞了文章2五塊,二號使用者有一張會員卡2、二號使用者打賞了文章1二十塊,注意,這已經是我簡略了的版本,可以簡單的想像會有打賞日期、文章發表日期等等,這張表就會又肥又雜,雖然好像遇到什麼問題的時候新增一個對應種類就好,但這樣超級不正規化,實在非常有失關聯式資料庫的意義(要不然就直接用NoSQL阿XD)。上表有時候可能會簡化成下表,利用某些欄位在不同種類其實代表不同意思來處理,但還是很肥啦

使用者阿哩阿砸table
Key 使用者key 對應種類 外來key 該種類日期 打賞 ...
1 1 會員卡 1 2018/10/08 x
2 1 作者 1 2018/10/08 x
3 2 會員卡 2 2018/10/08 x
4 2 打賞 1 2018/10/08 20
5 1 打賞 2 2018/10/08 5

 

-------------------------------------------------------------------------------------------------------

它:「我愛寫程式ㄟ!」

我:「你...愛寫程式?」

它:「是阿!」

我:「你...愛用程式解決問題?愛寫出被大家所使用的程式?愛能夠用程式改變世界的力量?」

它:「沒錯!你說得太...」

我:「你愛日以繼夜焚膏繼晷的寫程式?你愛無法離座坐到屁股長痔瘡的寫程式?你愛寫程式愛到奮不顧身?」

它:「你...」

我:「你愛想破頭想到拿頭去撞牆想到掉光頭髮的寫程式?你愛被時程、需求、主管、客戶追著跑的寫程式?你愛寫程式即使程式不愛妳?」

我:「你愛你明明知道這樣不是好的寫法卻仍然得這樣寫?你愛維護別人寫出來的爛程式?你愛聽不懂的主管胡說八道該怎麼寫?」

它:「你在說什麼東西啦!你也沒有這樣子阿!」

我:「是阿,所以我不愛寫程式。」

它:「你懂不懂寫程式阿?」

我:「:)」