感謝大佬:https://blog.csdn.net/w_linux/article/details/79655073
說說關於數據庫中一個重要的知識點——約束
一、什么是約束
約束英文:constraint
約束實際上就是表中數據的限制條件
二、約束作用
表在設計的時候加入約束的目的就是為了保證表中的記錄完整和有效
- 比如name字段中要讓其用戶名不重復,這就需要添加約束。或者必須注冊的時候需要添加郵箱等
三、約束種類
- 非空約束(not null)
- 唯一性約束(unique)
- 主鍵約束(primary key) PK
- 外鍵約束(foreign key) FK
- 檢查約束(目前MySQL不支持、Oracle支持)
下面將逐一介紹以上約束
四、非空約束
用not null約束的字段不能為null值,必須給定具體的數據
創建表,給字段添加非空約束(創建用戶表,用戶名不能為空)
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null
-
-> );
-
Query OK,
0
rows affected (0.08 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
如果沒有插入name字段數據,則會報錯
-
mysql> insert
into t_user (id) values(
1);
-
ERROR
1364 (HY000): Field
'name' doesn't have a default value
- 1
- 2
- 3
五、唯一性約束
unique約束的字段,具有唯一性,不可重復,但可以為null
創建表,保證郵箱地址唯一(列級約束)
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> email varchar(128) unique
-
-> );
-
Query OK,
0
rows affected (0.03 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
1、表級約束
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> email varchar(128),
-
-> unique(email)
-
-> );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
如果插入相同email會報錯
-
mysql>
insert into t_user(id,name,email) values(1,'xlj','932834897@qq.com');
-
Query OK,
1
row affected (0.00 sec)
-
-
mysql> insert into t_user(id,name,email) values(2,'jay','932834897@qq.com');
-
ERROR
1062 (
23000): Duplicate entry
'932834897@qq.com'
for key
'email'
- 1
- 2
- 3
- 4
- 5
- 6
2、使用表級約束,給多個字段聯合約束
聯合約束,表示兩個或以上的字段同時與另一條記錄相等,則報錯
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> email varchar(128),
-
-> unique(name,email)
-
-> );
-
Query OK,
0
rows affected (0.01 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
插入第一條數據
-
mysql>
insert into t_user(id,name,email) values(1,'xxx','qq.com');
-
Query OK,
1
row affected (0.05 sec)
-
- 1
- 2
- 3
插入第二條數據如果是與聯合字段中的一條相同另一條相同,也是可以的
-
mysql>
insert into t_user(id,name,email) values(2,'mmm','qq.com');
-
Query OK,
1
row affected (0.05 sec)
-
- 1
- 2
- 3
插入第三條數據,如果與聯合字段都相同,則報錯
-
mysql>
insert into t_user(id,name,email) values(3,'mmm','qq.com');
-
ERROR
1062 (
23000): Duplicate entry
'mmm-qq.com'
for key
'name'
- 1
- 2
- 3
3、表級約束可以給約束起名字(方便以后通過這個名字來刪除這個約束)
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> email varchar(128),
-
-> constraint t_user_email_unique unique(email)
-
-> );
-
Query OK,
0
rows affected (0.06 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
constraint是約束關鍵字,t_user_email_unique自己取的名字
例:用戶名既不能為空,也不能重復
name varchar(32) not null unique
- 1
- 2
六、主鍵約束(primary key)PK
表設計時一定要有主鍵
1、主鍵涉及術語
- 主鍵約束
- 主鍵字段
- 主鍵值
2、以上三種術語關系
表中的某個字段添加主鍵約束后,該字段為主鍵字段,主鍵字段中出現的每一個數據都稱為主鍵值
3、主鍵約束與“not null unique”區別
給某個字段添加主鍵約束之后,該字段不能重復也不能為空,效果和”not null unique”約束相同,但是本質不同。
主鍵約束除了可以做到”not null unique”之外,還會默認添加”索引——index”
4、一張表應該有主鍵字段,如果沒有,表示該表無效
- 主鍵值:是當前行數據的唯一標識、是當前行數據的身份證號
- 即使表中兩行記錄相關數據相同,但由於主鍵值不同,所以也認為是兩行不同的記錄
5、按主鍵約束的字段數量分類
無論是單一主鍵還是復合主鍵,一張表主鍵約束只能有一個(約束只能有一個,但可以作用到好幾個字段)
- 單一主鍵:給一個字段添加主鍵約束
- 復合主鍵:給多個字段聯合添加一個主鍵約束(只能用表級定義)
單一主鍵(列級定義)
-
mysql>
create table t_user(
-
-> id int(10) primary key,
-
-> name varchar(32)
-
-> );
-
Query OK,
0
rows affected (0.07 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
單一主鍵(表級定義)
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> constraint t_user_id_pk primary key(id)
-
-> );
-
Query OK,
0
rows affected (0.01 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
復合主鍵(表級定義)
-
mysql>
create table t_user(
-
-> id int(10),
-
-> name varchar(32) not null,
-
-> email varchar(128) unique,
-
-> primary key(id,name)
-
-> );
-
Query OK,
0
rows affected (0.05 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
6、在MySQL數據庫提供了一個自增的數字,專門用來自動生成主鍵值,主鍵值不用用戶維護,自動生成,自增數從1開始,以1遞增(auto_increment)
-
mysql>
create table t_user(
-
-> id int(10) primary key auto_increment,
-
-> name varchar(32) not null
-
-> );
-
Query OK,
0
rows affected (0.03 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
插入兩行記錄,id主鍵值會自動增加
-
mysql>
insert into t_user(name) values('jay');
-
Query OK,
1
row affected (0.04 sec)
-
-
mysql> insert into t_user(name) values('man');
-
Query OK,
1
row affected (0.00 sec)
-
-
-
mysql> select * from t_user;
-
+----+------+
-
| id | name |
-
+----+------+
-
|
1 | jay |
-
|
2 | man |
-
+----+------+
-
2
rows in set (0.00 sec)
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
七、外鍵約束(foreign key)FK
只能是表級定義(如以下例子)
foreign key(classno) references t_class(cno)
- 1
- 2
什么是外鍵
若有兩個表A、B,id是A的主鍵,而B中也有id字段,則id就是表B的外鍵,外鍵約束主要用來維護兩個表之間數據的一致性。
A為基本表,B為信息表
1、外鍵涉及到的術語
- 外鍵約束
- 外鍵字段
- 外鍵值
2、外鍵約束、外鍵字段、外鍵值之間的關系
某個字段添加外鍵約束之后,該字段稱為外鍵字段,外鍵字段中每個數據都是外鍵值
3、按外鍵約束的字段數量分類
- 單一外鍵:給一個字段添加外鍵約束
- 復合外鍵:給多個字段聯合添加一個外鍵約束
4、一張表可以有多個外鍵字段(與主鍵不同)
5、分析場景
設計數據庫表,用來存儲學生和班級信息
兩種方案
方案一:將學生信息和班級信息存儲到一張表
sno sname classno cname 1 jay 100 浙江省第一中學高三1班 2 lucy 100 浙江省第一中學高三1班 3 king 200 浙江省第一中學高三2班
- 1
- 2
- 3
- 4
- 5
缺點:數據冗余,比如cname字段的數據重復太多
方案二:將學生信息和班級信息分開兩張表存儲
學生表(添加單一外鍵)
sno(pk) sname classno(fk) 1 jack 100 2 lucy 100 3 king 200
- 1
- 2
- 3
- 4
- 5
班級表
cno(pk) cname 100 浙江省第一中學高三1班 200 浙江省第一中學高三2班
- 1
- 2
- 3
- 4
結論
為了保證學生表中的classno字段中的數據必須來自於班級表中的cno字段中的數據,有必要給學生表中的classno字段添加外鍵約束
注意點
- 外鍵值可以為null
- 外鍵字段去引用一張表的某個字段的時候,被引用的字段必須具有unique約束
- 有了外鍵引用之后,表分為父表和子表
- 班級表:父表
- 學生表:子表
- 創建先創建父表
- 刪除先刪除子表數據
- 插入先插入父表數據
存儲學生班級信息
-
mysql> drop table
if exists t_student;
-
mysql> drop table
if exists t_class;
-
-
mysql>
create table t_class(
-
-> cno int(10) primary key,
-
-> cname varchar(128) not null unique
-
-> );
-
-
mysql>
create table t_student(
-
-> sno int(10) primary key auto_increment,
-
-> sname varchar(32) not null,
-
-> classno int(3),
-
-> foreign key(classno) references t_class(cno)
-
-> );
-
-
mysql>
insert into t_class(cno,cname) values(100,'aaaaaaxxxxxx');
-
mysql>
insert into t_class(cno,cname) values(200,'oooooopppppp');
-
mysql>
insert into t_student(sname,classno) values('jack',100);
-
mysql>
insert into t_student(sname,classno) values('lucy',100);
-
mysql>
insert into t_student(sname,classno) values('king',200);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
班級表t_class
-
mysql> select * from t_class;
-
+-----+--------------+
-
| cno | cname
|
-
+-----+--------------+
-
|
100
| aaaaaaxxxxxx |
-
| 200 | oooooopppppp
|
-
+-----+--------------+
-
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
學生表t_student
-
mysql> select * from t_student;
-
+-----+-------+---------+
-
| sno | sname
| classno |
-
+-----+-------+---------+
-
| 1 | jack
| 100 |
-
| 2 | lucy
| 100 |
-
| 3 | king
| 200 |
-
+-----+-------+---------+
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上表中找出每個學生的班級名稱
-
mysql> select s.*,c.* from t_student s join t_class c on s.classno=c.cno;
-
+-----+-------+---------+-----+--------------+
-
| sno | sname
| classno | cno
| cname |
-
+-----+-------+---------+-----+--------------+
-
| 1 | jack
| 100 |
100
| aaaaaaxxxxxx |
-
| 2 | lucy
| 100 |
100
| aaaaaaxxxxxx |
-
| 3 | king
| 200 |
200
| oooooopppppp |
-
+-----+-------+---------+-----+--------------+
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
結論
以上是典型的一對多的設計:在多個地方加外鍵(子表加外鍵)
轉載出處 淺然的專欄 https://blog.csdn.net/w_linux/article/details/79655073
