約束(CONSTRAINT)
什么是約束?
是一種限制,對某一個東西的限制。例如憲法規定了你違反的事情你是不能做的。這就是一種約束
數據庫的約束,是對數據的安全性,完整性的保證
mysql中的約束有哪些?
1. unique key(普通約束)
唯一性約束,表示這個不能出現重復的值,
# 完整的建表語句 create table table_name(字段名 字段類型[長度] [約束]) charset utf8; # 創建表 mysql> create table student( -> naem char(20) not null, -> gender enum("g","b") default "b", -> id int unique) charset utf8; Query OK, 0 rows affected (0.23 sec) # 查看表結構 mysql> desc student; +--------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+---------------+------+-----+---------+-------+ | naem | char(20) | NO | | NULL | | | gender | enum('g','b') | YES | | b | | | id | int(11) | YES | UNI | NULL | | +--------+---------------+------+-----+---------+-------+ 3 rows in set (0.01 sec) mysql> insert into student values("潘立府",null,null); Query OK, 1 row affected (0.07 sec) mysql> select * from student; +-----------+--------+------+ | naem | gender | id | +-----------+--------+------+ | 潘立府 | NULL | NULL | +-----------+--------+------+ 1 row in set (0.00 sec) # 對name字段插入null時,提示報錯 mysql> insert into student values(null,null,null); ERROR 1048 (23000): Column 'name' cannot be null # 對name字段給定值后,發現能夠插入數據 mysql> insert into student values("張三",null,null); Query OK, 1 row affected (0.06 sec) # 查看數據 mysql> select * from student; +--------+--------+------+ | name | gender | id | +--------+--------+------+ | 張三 | NULL | NULL | +--------+--------+------+ 1 row in set (0.00 sec) # 發現問題:id字段為唯一性約束,不能出現重復值,但是重復插入null值,唯一約束沒有生效 mysql> insert into student values("李四",null,null); Query OK, 1 row affected (0.07 sec) mysql> select * from student; +--------+--------+------+ | name | gender | id | +--------+--------+------+ | 張三 | NULL | NULL | | 李四 | NULL | NULL | +--------+--------+------+ 2 rows in set (0.00 sec) # 此時想把id字段的屬性改為:唯一性約束 + not null ,但是發現報錯,原因:表中已經存在null值。 mysql> alter table student modify id int unique not null; ERROR 1062 (23000): Duplicate entry '0' for key 'id' # 於是刪除數據,再修改id的屬性 mysql> delete from student; Query OK, 2 rows affected (0.29 sec) mysql> alter table student modify id int unique not null; Query OK, 0 rows affected, 1 warning (0.56 sec) Records: 0 Duplicates: 0 Warnings: 1 mysql> desc student; +--------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+---------------+------+-----+---------+-------+ | name | char(20) | NO | | NULL | | | gender | enum('g','b') | YES | | b | | | id | int(11) | NO | PRI | NULL | | +--------+---------------+------+-----+---------+-------+ 3 rows in set (0.01 sec) # 此時發現,插入數據時,id不能為null了。 mysql> insert into student values("李四",null,null); ERROR 1048 (23000): Column 'id' cannot be null
結論:字段只設置unique唯一性約束,null值依然能夠插入,原因:mysql不能對null進行比較
2. not null
非空約束,表示這個字段的值不能為空
例如:賬戶名、密碼等
3. default
默認值,用於給某一個字段設置默認值
4. primary key 主鍵約束
主鍵約束,從約束角度來看,主鍵等同於非空 + 唯一
主鍵與普通約束的區別:# 創建主鍵字段:id mysql> create table persong( -> id char(19) primary key, -> name char(20)); Query OK, 0 rows affected (0.46 sec) # OK mysql> insert into persong values("1","rose"); Query OK, 1 row affected (0.29 sec) # 主鍵沖突 mysql> insert into persong values("1","rose"); ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> desc persong; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | char(19) | NO | PRI | NULL | | | name | char(20) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
主鍵的特點:
主鍵是一種索引,索引的作用是加速查詢效率。因此主鍵約束能加速我們查詢的效率。
在執行sql語句的前面加上:explain 可查看sql語句的執行計划
主鍵對於innodb引擎來說是必須要的,沒有不行。即使我們在創建innodb引擎的表,沒有創建主鍵,系統也會自動創建一個隱藏的主鍵。
一個表中只能存在一個主鍵
auto_increment(自增長)
mysql> create table teacher (id int primary key auto_increment,name char(20)); Query OK, 0 rows affected (0.47 sec) # 第一種插入方法 mysql> insert into teacher values(null,"jack"); Query OK, 1 row affected (0.28 sec) mysql> insert into teacher values(null,"rose"); Query OK, 1 row affected (0.29 sec) mysql> insert into teacher values(null,"panlifu"); Query OK, 1 row affected (0.29 sec) mysql> insert into teacher values(null,"lt"); Query OK, 1 row affected (0.06 sec) mysql> select * from teacher; +----+---------+ | id | name | +----+---------+ | 1 | jack | | 2 | rose | | 3 | panlifu | | 4 | lt | +----+---------+ 4 rows in set (0.00 sec) # 第二種方式 插入數據 mysql> insert into teacher(name) values("xs"); Query OK, 1 row affected (0.29 sec) mysql> select * from teacher; +----+---------+ | id | name | +----+---------+ | 1 | jack | | 2 | rose | | 3 | panlifu | | 4 | lt | | 5 | xs | +----+---------+ 5 rows in set (0.00 sec) # 當auto_increment 約束 primary key時,即使我們插入數據指定為自增列為空,系統也會幫助我們自動增長。
5. foreign key 外鍵約束
一. 數據出現了大量的重復
二. 數據結構環混亂(耦合度高)
三. 當后期修改數據時,由於有大量的重復數據,必須每個都修改
如何創建外鍵索引:
第一階段
應該先確定主鍵所在表的數據結構。例如:部門表(主表)
create table dept( id int primary key auto_increment, name char(20), job char(50), manager char(30) ) charset utf8;
- 在確認外鍵所在表的數據結構。例如:員工表(從表、子表)
create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int ) charset utf8;
這里存在缺點:部門表和員工表之間沒有建立聯系,目前部門表修改數據,員工表無感知
第二階段
- 對員工表進行約束(跟部門表建立聯系)
create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int, foreign key(dept_id) references dept(id) ) charset utf8; # dept_id 表示員工表的外鍵字段 # dept 表示要關聯的哪個表,這里指部門表 # references 引用的意思 # dept(id) 表示要關聯dept表中的id字段
這樣從表就跟主表建立了外鍵聯系。
第三階段:建立級聯操作
因為外鍵存在第4點和第5點的原因,因此才有了級聯的操作,來簡化對數據庫的管理
另外級聯是建立在子表中的。
# 主庫 create table dept( id int primary key auto_increment, name char(20), job char(50), manager char(30) ) charset utf8; # 子表 create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int, foreign key(dept_id) references dept(id) on update cascade on delete cascade ) charset utf8; # one delete cascade 應對 特征中的第4點 # on update cascade 應對 特征中的第5點
總結特征:
外鍵字段的數據類型必須跟關聯表的字段類型 相近或者相等。例如主鍵的數據類型為int,外鍵的數據類型可以為logint等其他的整型數據。但是不能為字符串,date等數據
在從表中插入數據時,如果主表不存在對應的數據,那么會導致插入失敗。
create table dept( id int primary key auto_increment, name char(20), job char(50), manager char(30) ) charset utf8; create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int, foreign key(dept_id) references dept(id) ) charset utf8; mysql> insert into teacher values(null,"bgon","m",1); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`plf`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
- 從表更新外鍵時,必須保證外鍵的值在主表中是存在的
create table dept( id int primary key auto_increment, name char(20), job char(50), manager char(30) ) charset utf8; create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int, foreign key(dept_id) references dept(id) ) charset utf8; mysql> select *from dept; Empty set (0.00 sec) mysql> select * from teacher; Empty set (0.00 sec) mysql> insert into dept values(null,"教學部","教學","bgon"); Query OK, 1 row affected (0.29 sec) mysql> insert into dept values(null,"銷售部","銷售","plf"); Query OK, 1 row affected (0.07 sec) mysql> select *from dept; +----+-----------+--------+---------+ | id | name | job | manager | +----+-----------+--------+---------+ | 1 | 教學部 | 教學 | bgon | | 2 | 銷售部 | 銷售 | plf | +----+-----------+--------+---------+ 2 rows in set (0.00 sec) mysql> insert into teacher values(null,'張三',"男",1); Query OK, 1 row affected (0.30 sec) mysql> select *from teacher; +----+--------+--------+---------+ | id | name | gender | dept_id | +----+--------+--------+---------+ | 1 | 張三 | 男 | 1 | +----+--------+--------+---------+ 1 row in set (0.00 sec) # 當將dept_id更新為3時,報錯。原因:主表中並沒有編號為3的數據 mysql> update teacher set dept_id = 3 where id =1; ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`)) mysql>
- 刪除主表記錄前,要保證從表中沒有外鍵關聯被刪除的id(可以級聯)
mysql> select *from dept; +----+-----------+--------+---------+ | id | name | job | manager | +----+-----------+--------+---------+ | 1 | 教學部 | 教學 | bgon | | 2 | 銷售部 | 銷售 | plf | +----+-----------+--------+---------+ 2 rows in set (0.00 sec) mysql> select *from teacher; +----+--------+--------+---------+ | id | name | gender | dept_id | +----+--------+--------+---------+ | 1 | 張三 | 男 | 1 | +----+--------+--------+---------+ 1 row in set (0.00 sec) mysql> delete from dept where id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
- 更新主表記錄的主鍵時,要保證從表中沒有外鍵關聯被刪除的id(可以級聯)
mysql> select *from dept; +----+-----------+--------+---------+ | id | name | job | manager | +----+-----------+--------+---------+ | 1 | 教學部 | 教學 | bgon | | 2 | 銷售部 | 銷售 | plf | +----+-----------+--------+---------+ 2 rows in set (0.00 sec) mysql> select *from teacher; +----+--------+--------+---------+ | id | name | gender | dept_id | +----+--------+--------+---------+ | 1 | 張三 | 男 | 1 | +----+--------+--------+---------+ 1 row in set (0.00 sec) # 當更新主表編號為1的部門時,因為編號1部門下有一個人,所以不能更新 mysql> update dept set id = 3 where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`)) mysql>
- 必須先創建主表,子表才能用外鍵
- 刪除表的操作,先刪除從表,再刪除主表
mysql> select *from dept; +----+-----------+--------+---------+ | id | name | job | manager | +----+-----------+--------+---------+ | 1 | 教學部 | 教學 | bgon | | 2 | 銷售部 | 銷售 | plf | +----+-----------+--------+---------+ 2 rows in set (0.00 sec) mysql> select *from teacher; +----+--------+--------+---------+ | id | name | gender | dept_id | +----+--------+--------+---------+ | 1 | 張三 | 男 | 1 | +----+--------+--------+---------+ 1 row in set (0.00 sec) # 不能刪除 mysql> drop table dept; ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
級聯操作
產生的原因:
當我們需要刪除部門(主表)信息時,必須先刪除從表中關聯的數據,很麻煩。
級聯操作指的就是,當你操作主表時,自動操作從表
兩種級聯的定義方式
一. 在表定義階段進行定義:
-
級聯的刪除
create table student_b( class_id int, name char(10), age int, foreign key(class_id) references class_b(id) on delete cascade ) charset utf8;
-
級聯的更新
create table student_b( class_id int, name char(10), age int, foreign key(class_id) references class_b(id) on update cascade ) charset utf8;
-
級聯的刪除和更新
create table teacher( id int primary key auto_increment, name char(20), gender char(21), dept_id int, foreign key(dept_id) references dept(id) on update cascade on delete cascade ) charset utf8;
二. 表存在的情況下,先將之前的外鍵刪除掉,然后通過alter增加外鍵級聯:
# 刪除外鍵
mysql> alter table teacher drop foreign key 外鍵的ID;
# 增加外鍵並增加級聯刪除和更新
mysql> alter table teacher add constraint dept_id foreign key(dept_id) references dept(id) on delete cascade on update cascade;