MySQL之約束


約束(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)

主鍵的特點:

  1. 主鍵是一種索引,索引的作用是加速查詢效率。因此主鍵約束能加速我們查詢的效率。

    在執行sql語句的前面加上:explain 可查看sql語句的執行計划

  2. 主鍵對於innodb引擎來說是必須要的,沒有不行。即使我們在創建innodb引擎的表,沒有創建主鍵,系統也會自動創建一個隱藏的主鍵。

  3. 一個表中只能存在一個主鍵


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 外鍵約束

一. 數據出現了大量的重復

二. 數據結構環混亂(耦合度高)

三. 當后期修改數據時,由於有大量的重復數據,必須每個都修改

如何創建外鍵索引:

第一階段
  1. 應該先確定主鍵所在表的數據結構。例如:部門表(主表)

    create table dept(
    	id int primary key auto_increment,
        name char(20),
        job char(50),
        manager char(30)
    ) charset utf8;
    
    1. 在確認外鍵所在表的數據結構。例如:員工表(從表、子表)
create table teacher(
   	id int primary key auto_increment,
       name char(20),
       gender char(21),
       dept_id int
   ) charset utf8;

這里存在缺點:部門表和員工表之間沒有建立聯系,目前部門表修改數據,員工表無感知


第二階段
  1. 對員工表進行約束(跟部門表建立聯系)
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點

總結特征:

  1. 外鍵字段的數據類型必須跟關聯表的字段類型 相近或者相等。例如主鍵的數據類型為int,外鍵的數據類型可以為logint等其他的整型數據。但是不能為字符串,date等數據

  2. 在從表中插入數據時,如果主表不存在對應的數據,那么會導致插入失敗。

   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`))
   
  1. 從表更新外鍵時,必須保證外鍵的值在主表中是存在的
   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>
  1. 刪除主表記錄前,要保證從表中沒有外鍵關聯被刪除的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`))
  1. 更新主表記錄的主鍵時,要保證從表中沒有外鍵關聯被刪除的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>
  1. 必須先創建主表,子表才能用外鍵
   
  1. 刪除表的操作,先刪除從表,再刪除主表
   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

級聯操作

產生的原因:

當我們需要刪除部門(主表)信息時,必須先刪除從表中關聯的數據,很麻煩。

級聯操作指的就是,當你操作主表時,自動操作從表

兩種級聯的定義方式

一. 在表定義階段進行定義:
  1. 級聯的刪除

    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;
    
  2. 級聯的更新

    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;
    
  3. 級聯的刪除和更新

    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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM