產(chǎn)品經(jīng)理從0開(kāi)始學(xué)SQL(五)-表設(shè)計(jì)
目錄
1、數(shù)據(jù)庫(kù)約束與常見(jiàn)操作
2、建表規(guī)范
ps:以下講解均基于mysql語(yǔ)言。
數(shù)據(jù)庫(kù)約束與常見(jiàn)操作
一、主鍵
我們知道,一個(gè)表由n行記錄組成。
1、概述
關(guān)系表都有一個(gè)約束:每一行記錄必須要有某個(gè)字段來(lái)唯一標(biāo)識(shí),能唯一標(biāo)記記錄的字段,稱(chēng)為主鍵。
假設(shè)有一張學(xué)生表:t_student
| id | name | class_id | mobile |
|---|---|---|---|
| 1 | 張三 | 2 | 130xxx |
| 2 | 李四 | 4 | 140xxx |
| 3 | 陳紅 | 3 | 150xxx |
上面這張表,id是主鍵,我們可以通過(guò)id來(lái)區(qū)分出每一個(gè)同學(xué):
id=1是張三,id=2是李四,id=3是陳紅
一個(gè)表必須要有主鍵。我們可以在建表的時(shí)候,用primary key標(biāo)識(shí)。比如:
create table t_student ( id int, name varchar(10), primary key (id));
2、主鍵字段的選擇
當(dāng)表已經(jīng)開(kāi)始使用并錄入數(shù)據(jù)后,最好不要再做更改了,因?yàn)楸淼闹麈I可能已經(jīng)在其他表里用做外鍵關(guān)聯(lián)或者已經(jīng)在業(yè)務(wù)邏輯中使用。
所以定義主鍵最好不要使用業(yè)務(wù)字段,業(yè)務(wù)字段發(fā)生變更的概率比較大,比如學(xué)生的手機(jī)號(hào)碼、學(xué)生的身份證都是可能發(fā)生變化的。
我們可以使用默認(rèn)的自增字段來(lái)做主鍵,比如student表的id。
也可以使用基于時(shí)間和空間生成的uuid來(lái)做主鍵,uuid一般是業(yè)務(wù)邏輯里面生成來(lái)動(dòng)態(tài)插入數(shù)據(jù)表。
3、聯(lián)合主鍵
主鍵可以使用多個(gè)字段來(lái)標(biāo)記。但是不太建議使用。這樣在以后處理表關(guān)系或者業(yè)務(wù)邏輯時(shí),會(huì)增加復(fù)雜度。
二、外鍵
假設(shè)有一張學(xué)生表:t_student
| id | name | class_id | mobile |
|---|---|---|---|
| 1 | 張三 | 2 | 130xxx |
| 2 | 李四 | 4 | 140xxx |
| 3 | 陳紅 | 3 | 150xxx |
還有一張班級(jí)表:t_class
| id | class_name |
|---|---|
| 1 | 1班 |
| 2 | 2班 |
| 3 | 3班 |
| 4 | 4班 |
我們已經(jīng)能通過(guò)id來(lái)識(shí)別張三、李四。那么我們?cè)趺醋R(shí)別張三屬于哪個(gè)班級(jí),李四屬于哪個(gè)班級(jí)呢?這時(shí)我們可以使用外鍵。
在t_student表增加一列叫class_id來(lái)表示班級(jí)id。
我們通過(guò)關(guān)系:t_student.class_id=t_class.id可以看出,張三在1班,李四在4班,陳紅在3班。
通過(guò)外鍵我們可以看出,這2張表是一個(gè)1對(duì)多的關(guān)系。這里的“多”指的是學(xué)生表,“1”指的是班級(jí)表,含義是一個(gè)學(xué)生只可以對(duì)應(yīng)一個(gè)班級(jí),但是一個(gè)班級(jí)可以對(duì)應(yīng)多個(gè)學(xué)生。
那如果是多對(duì)多的關(guān)系該如何實(shí)現(xiàn)呢?假設(shè)有一張學(xué)生選修的課程表:t_course
| id | course_name |
|---|---|
| 1 | 高等數(shù)學(xué) |
| 2 | 物理 |
| 3 | 政治 |
| 4 | 算法 |
一個(gè)學(xué)生可選修多門(mén)課程,一個(gè)課程也可以被多名學(xué)生選擇學(xué)習(xí)。這是一個(gè)多對(duì)多的關(guān)系。
一般會(huì)通過(guò)一個(gè)中間表來(lái)實(shí)現(xiàn)。
我們建立一個(gè)中間表叫做:t_student_course
| id | course_id | student_id |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 2 | 2 | 4 |
| 3 | 3 | 1 |
| 4 | 4 | 2 |
表里一般要存儲(chǔ)2個(gè)表的主鍵,如上的course_id和student_id。從表中我們就可以看出,學(xué)生id=1的張三選修了兩門(mén)課程,分別是數(shù)學(xué)和政治。學(xué)生id=2的李四也選修了兩門(mén)課程,分別是數(shù)據(jù)和算法。
還剩下一種表關(guān)系是1對(duì)1的關(guān)系,假設(shè)還有一張學(xué)生信息明細(xì)表,存儲(chǔ)的是學(xué)生更詳細(xì)的信息的表:t_student_detail
| id | student_id | address | age |
|---|---|---|---|
| 1 | 1 | 深圳南山 | 男 |
| 2 | 2 | 深圳福田 | 男 |
| 3 | 3 | 深圳龍崗 | 女 |
我們可以看出,一個(gè)學(xué)生對(duì)應(yīng)一個(gè)詳細(xì)信息。但是如果t_student_detail表里面只有一個(gè)字段或者2個(gè)字段的話,根據(jù)業(yè)務(wù)情況,也可以把這些字段納入到t_student表中。
其實(shí)上述的學(xué)生詳細(xì)明細(xì)表的做法,是一個(gè)提升表查詢效率的做法。當(dāng)t_student表的數(shù)據(jù)量比較大的時(shí)候,而且查詢學(xué)生信息可能往往只是那幾個(gè)字段,就可以通過(guò)分表的方式去提升查詢性能。
小結(jié):表之間的關(guān)系有3種,分別是1對(duì)1,1對(duì)多,多對(duì)多。1對(duì)1可以通過(guò)增加一個(gè)字段或者建立另一張表通過(guò)外鍵關(guān)聯(lián)。1對(duì)多可以通過(guò)建立另一張表通過(guò)外鍵關(guān)聯(lián)。而多對(duì)多可以通過(guò)建立一張中間表和其他2張表的外鍵關(guān)聯(lián)。
三、索引
索引按用途可以分為2種,一種是用于提升查詢速度的查詢索引,另一種是約束唯一性作用的唯一索引。
1、查詢索引
一張數(shù)據(jù)表中,可能有成千上萬(wàn)的數(shù)據(jù),如果想提高查詢速度,那么通過(guò)給字段創(chuàng)建索引是提高查詢速度的一種方式。
如果t_student表中,name是經(jīng)常要查詢的字段,那我們可以給name創(chuàng)建一個(gè)索引。
ALTER TABLE t_student ADD INDEX idx_name (name)
2、唯一索引
唯一索引表示的是字段的值是唯一的。
比如學(xué)生的手機(jī)號(hào)碼,身份證這些業(yè)務(wù)字段,都是唯一的,如果給這些字段加上唯一索引約束,那么當(dāng)你往學(xué)生表里插入重復(fù)的手機(jī)號(hào)碼或者身份證時(shí),數(shù)據(jù)庫(kù)就會(huì)報(bào)錯(cuò)阻止你的操作,起到保護(hù)數(shù)據(jù)唯一性的作用。
對(duì)單個(gè)字段添加唯一索引:mobile字段
ALTER TABLE t_student ADD UNIQUE INDEX uni_mobile (mobile);
對(duì)多個(gè)字段添加聯(lián)合唯一索引:mobile和card_id字段
ALTER TABLE t_student ADD UNIQUE INDEX uni_mobile_card (mobile,card_id);
四、默認(rèn)值
我們可以給字段設(shè)置默認(rèn)值,但是默認(rèn)值跟數(shù)據(jù)類(lèi)型必須是匹配的。比如你是一個(gè)int整型,不能設(shè)置一個(gè)字符串類(lèi)型的值。
比如設(shè)置時(shí)間字段的默認(rèn)值為當(dāng)前時(shí)間戳:
create table t_student ( create_time timestamp default current_timestamp );
五、NOT NULL 約束
null不是數(shù)據(jù)類(lèi)型,它是列的一個(gè)屬性。
null表示的是空,如果你不允許你的字段值為空,則添加not null約束
比如約束學(xué)生表的名字不能為空:
create table t_student (name VARCHAR(22) NOT NULL)
建表規(guī)范
建表三范式可能大家都知道。一般建表都要遵守三范式原則。
一、第一范式
要求有主鍵,并且要求每一個(gè)字段都遵守原子性不可再分。
二、第二范式
滿足第一范式的前提下,要求所有非主鍵字段完全依賴(lài)主鍵,不能產(chǎn)生部分依賴(lài)。
舉個(gè)例子:假設(shè)有一張學(xué)生表:t_student
| 學(xué)生編號(hào) | 老師編號(hào) | 學(xué)生姓名 | 老師姓名 |
|---|---|---|---|
| s1001 | t1001 | 張三 | 葉老師 |
| s1002 | t1001 | 李四 | 葉老師 |
| s1003 | t1003 | 陳紅 | 李老師 |
這個(gè)表以學(xué)生編號(hào)和老師編號(hào)為聯(lián)合主鍵。
該表會(huì)出現(xiàn)大量的冗余,冗余字段為“學(xué)生姓名”和“教師姓名”,出現(xiàn)冗余主要是學(xué)生姓名部分依賴(lài)了主鍵的一個(gè)字段學(xué)生編號(hào),而沒(méi)有依賴(lài)教師編號(hào),而教師姓名部分依賴(lài)了主鍵的一個(gè)字段教師編號(hào),這就是第二范式部分依賴(lài)。
所以這張表是不合理的,學(xué)生和老師之間的關(guān)系應(yīng)該是多對(duì)多的關(guān)系,我們應(yīng)該通過(guò)建立3張表來(lái)實(shí)現(xiàn),分別是
t_student(學(xué)生表)
t_teacher(老師表)
t_student_teacher(學(xué)生老師中間表)
三、第三范式
滿足第二范式的前提下,所有非主鍵字段和主鍵字段之間不能產(chǎn)生傳遞依賴(lài)。某個(gè)字段依賴(lài)于主鍵,而有其他字段依賴(lài)于該字段。這就是傳遞依賴(lài)。(不詳細(xì)描述了,道理跟第二范式的例子類(lèi)似)
---- END ----
免費(fèi)星球:建立了一個(gè)產(chǎn)品+技術(shù)資料庫(kù)星球,每周會(huì)定期更新資料庫(kù),內(nèi)容包括最新的行業(yè)報(bào)告、電子書(shū)、原型等,關(guān)注公眾號(hào)并回復(fù)【星球】免費(fèi)進(jìn)入!
以下是星球資料部分截圖:


?? 愛(ài)心三連擊
1、看到這里了就點(diǎn)個(gè)在看支持下吧,你的點(diǎn)贊/在看/分享是我持續(xù)創(chuàng)作的動(dòng)力。
2、關(guān)注公眾號(hào)【產(chǎn)品的技術(shù)小課】,回復(fù)【加群】加入產(chǎn)品技術(shù)交流群
3、也可添加我微信【yss627144】,一起成長(zhǎng)。
