1. 程式人生 > 其它 >MySQL學習筆記:十三、約束

MySQL學習筆記:十三、約束

1. 約束(constraint)概述

1.1 為什麼需要約束

資料完整性(Data Integrity)是指資料的精確性(Accuracy)和可靠性(Reliability)。它是防止資料庫中存在不符合語義規定的資料和防止因錯誤資訊的輸入輸出造成無效操作或錯誤資訊而提出的。

為了保證資料的完整性,SQL規範以約束的方式對表資料進行額外的條件限制。從以下四個方面考慮:

  • 實體完整性(Entity Integrity):例如,同一個表中,不能存在兩條完全相同無法區分的記錄
  • 域完整性(Domain Integrity):例如:年齡範圍0-120,性別範圍“男/女”
  • 引用完整性(Referential Integrity)
    :例如:員工所在部門,在部門表中要能找到這個部門
  • 使用者自定義完整性(User-defined Integrity):例如:使用者名稱唯一、密碼不能為空等,本部門經理的工資不得高於本部門職工的平均工資的5倍。

1.2 什麼是約束

約束是表級的強制規定。

可以在建立表時規定約束(通過 CREATE TABLE 語句),或者在表建立之後通過 ALTER TABLE 語句規定約束

1.3 約束的分類

  • **根據約束資料列的限制,**約束可分為:
    • 單列約束:每個約束只約束一列
    • 多列約束:每個約束可約束多列資料
  • 根據約束的作用範圍,約束可分為:
    • 列級約束:只能作用在一個列上,跟在列的定義後面
    • 表級約束:可以作用在多個列上,不與列一起,而是單獨定義
位置 支援的約束型別 是否可以起約束名
列級約束 列的後面 語法都支援,但外來鍵沒有效果 不可以
表級約束 所有列的下面 預設和非空不支援,其他支援 可以(主鍵沒有效果)
  • 根據約束起的作用,約束可分為:
    • NOT NULL 非空約束,規定某個欄位不能為空
    • UNIQUE 唯一約束規定某個欄位在整個表中是唯一的
    • PRIMARY KEY 主鍵(非空且唯一)約束
    • FOREIGN KEY 外來鍵約束
    • CHECK 檢查約束
    • DEFAULT 預設值約束

注意: MySQL不支援check約束,但可以使用check約束,而沒有任何效果

  • 檢視某個表已有的約束
#information_schema資料庫名(系統庫)
#table_constraints表名稱(專門儲存各個表的約束)
SELECT * FROM information_schema.table_constraints 
WHERE table_name = '表名稱';

2. 非空約束

2.1 作用

限定某個欄位/某列的值不允許為空

2.2 關鍵字

NOT NULL

2.3 特點

  • 預設,所有的型別的值都可以是NULL,包括INT、FLOAT等資料型別

  • 非空約束只能出現在表物件的列上,只能某個列單獨限定非空,不能組合非空

  • 一個表可以有很多列都分別限定了非空

  • 空字串''不等於NULL,0也不等於NULL

2.4 新增非空約束

(1)建表時

CREATE TABLE 表名稱(
	欄位名  資料型別,
    欄位名  資料型別 NOT NULL,  
    欄位名  資料型別 NOT NULL
);

舉例:

CREATE TABLE emp(
id INT(10) NOT NULL,
NAME VARCHAR(20) NOT NULL,
sex CHAR NULL
);
CREATE TABLE student(
	sid int,
    sname varchar(20) not null,
    tel char(11) ,
    cardid char(18) not null
);
insert into student values(1,'張三','13710011002','110222198912032545'); #成功

insert into student values(2,'李四','13710011002',null);#身份證號為空
ERROR 1048 (23000): Column 'cardid' cannot be null

insert into student values(2,'李四',null,'110222198912032546');#成功,tel允許為空

insert into student values(3,null,null,'110222198912032547');#失敗
ERROR 1048 (23000): Column 'sname' cannot be null

(2)建表後

alter table 表名稱 modify 欄位名 資料型別 not null;

舉例:

ALTER TABLE emp
MODIFY sex VARCHAR(30) NOT NULL;
alter table student modify sname varchar(20) not null;

2.5 刪除非空約束

alter table 表名稱 modify 欄位名 資料型別 NULL;#去掉not null,相當於修改某個非註解欄位,該欄位允許為空

或 

alter table 表名稱 modify 欄位名 資料型別;#去掉not null,相當於修改某個非註解欄位,該欄位允許為空

舉例:

ALTER TABLE emp
MODIFY sex VARCHAR(30) NULL;
ALTER TABLE emp
MODIFY NAME VARCHAR(15) DEFAULT 'abc' NULL;

3. 唯一性約束

3.1 作用

用來限制某個欄位/某列的值不能重複。


3.2 關鍵字

UNIQUE

3.3 特點

  • 同一個表可以有多個唯一約束。
  • 唯一約束可以是某一個列的值唯一,也可以多個列組合的值唯一。
  • 唯一性約束允許列值為空。
  • 在建立唯一約束的時候,如果不給唯一約束命名,就預設和列名相同。
  • MySQL會給唯一約束的列上預設建立一個唯一索引。

3.4 新增唯一約束

(1)建表時

create table 表名稱(
	欄位名  資料型別,
    欄位名  資料型別  unique,  
    欄位名  資料型別  unique key,
    欄位名  資料型別
);
create table 表名稱(
	欄位名  資料型別,
    欄位名  資料型別,  
    欄位名  資料型別,
    [constraint 約束名] unique key(欄位名)
);

舉例:

create table student(
	sid int,
    sname varchar(20),
    tel char(11) unique,
    cardid char(18) unique key
);
CREATE TABLE t_course(
	cid INT UNIQUE,
	cname VARCHAR(100) UNIQUE,
	description VARCHAR(200)
);

CREATE TABLE USER(
 id INT NOT NULL,
 NAME VARCHAR(25),
 PASSWORD VARCHAR(16),
 -- 使用表級約束語法
 CONSTRAINT uk_name_pwd UNIQUE(NAME,PASSWORD)
);

表示使用者名稱和密碼組合不能重複

insert into student values(1,'張三','13710011002','101223199012015623');
insert into student values(2,'李四','13710011003','101223199012015624');
mysql> select * from student;
+-----+-------+-------------+--------------------+
| sid | sname | tel         | cardid             |
+-----+-------+-------------+--------------------+
|   1 | 張三  | 13710011002 | 101223199012015623 |
|   2 | 李四  | 13710011003 | 101223199012015624 |
+-----+-------+-------------+--------------------+
2 rows in set (0.00 sec)
insert into student values(3,'王五','13710011004','101223199012015624'); #身份證號重複
ERROR 1062 (23000): Duplicate entry '101223199012015624' for key 'cardid'

insert into student values(3,'王五','13710011003','101223199012015625'); 
ERROR 1062 (23000): Duplicate entry '13710011003' for key 'tel'

(2)建表後指定唯一鍵約束

#欄位列表中如果是一個欄位,表示該列的值唯一。如果是兩個或更多個欄位,那麼複合唯一,即多個欄位的組合是唯一的
#方式1:
alter table 表名稱 add unique key(欄位列表); 
#方式2:
alter table 表名稱 modify 欄位名 欄位型別 unique;

舉例:

ALTER TABLE USER 
ADD UNIQUE(NAME,PASSWORD);
ALTER TABLE USER 
ADD CONSTRAINT uk_name_pwd UNIQUE(NAME,PASSWORD);
ALTER TABLE USER 
MODIFY NAME VARCHAR(20) UNIQUE;

舉例:

create table student(
	sid int primary key,
    sname varchar(20),
    tel char(11) ,
    cardid char(18) 
);
alter table student add unique key(tel);
alter table student add unique key(cardid);

3.5 關於複合唯一約束

create table 表名稱(
	欄位名  資料型別,
    欄位名  資料型別,  
    欄位名  資料型別,
    unique key(欄位列表) #欄位列表中寫的是多個欄位名,多個欄位名用逗號分隔,表示那麼是複合唯一,即多個欄位的組合是唯一的
);
#學生表
create table student(
	sid int,	#學號
    sname varchar(20),			#姓名
    tel char(11) unique key,  #電話
    cardid char(18) unique key #身份證號
);

#課程表
create table course(
	cid int,  #課程編號
    cname varchar(20)     #課程名稱
);

#選課表
create table student_course(
    id int,
	sid int,
    cid int,
    score int,
    unique key(sid,cid)  #複合唯一
);
insert into student values(1,'張三','13710011002','101223199012015623');#成功
insert into student values(2,'李四','13710011003','101223199012015624');#成功
insert into course values(1001,'Java'),(1002,'MySQL');#成功
mysql> select * from student;
+-----+-------+-------------+--------------------+
| sid | sname | tel         | cardid             |
+-----+-------+-------------+--------------------+
|   1 | 張三  | 13710011002 | 101223199012015623 |
|   2 | 李四  | 13710011003 | 101223199012015624 |
+-----+-------+-------------+--------------------+
2 rows in set (0.00 sec)

mysql> select * from course;
+------+-------+
| cid  | cname |
+------+-------+
| 1001 | Java  |
| 1002 | MySQL |
+------+-------+
2 rows in set (0.00 sec)
insert into student_course values
(1, 1, 1001, 89),
(2, 1, 1002, 90),
(3, 2, 1001, 88),
(4, 2, 1002, 56);#成功
mysql> select * from student_course;
+----+------+------+-------+
| id | sid  | cid  | score |
+----+------+------+-------+
|  1 |    1 | 1001 |    89 |
|  2 |    1 | 1002 |    90 |
|  3 |    2 | 1001 |    88 |
|  4 |    2 | 1002 |    56 |
+----+------+------+-------+
4 rows in set (0.00 sec)
insert into student_course values (5, 1, 1001, 88);#失敗

#ERROR 1062 (23000): Duplicate entry '1-1001' for key 'sid'   違反sid-cid的複合唯一

3.5 刪除唯一約束

  • 新增唯一性約束的列上也會自動建立唯一索引。
  • 刪除唯一約束只能通過刪除唯一索引的方式刪除。
  • 刪除時需要指定唯一索引名,唯一索引名就和唯一約束名一樣。
  • 如果建立唯一約束時未指定名稱,如果是單列,就預設和列名相同;如果是組合列,那麼預設和()中排在第一個的列名相同。也可以自定義唯一性約束名。
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名'; #檢視都有哪些約束
ALTER TABLE USER 
DROP INDEX uk_name_pwd;

注意:可以通過 show index from 表名稱; 查看錶的索引

4. PRIMARY KEY 約束

4.1 作用

用來唯一標識表中的一行記錄。

4.2 關鍵字

primary key

4.3 特點

  • 主鍵約束相當於唯一約束+非空約束的組合,主鍵約束列不允許重複,也不允許出現空值。


  • 一個表最多隻能有一個主鍵約束,建立主鍵約束可以在列級別建立,也可以在表級別上建立。

  • 主鍵約束對應著表中的一列或者多列(複合主鍵)

  • 如果是多列組合的複合主鍵約束,那麼這些列都不允許為空值,並且組合的值不允許重複。

  • MySQL的主鍵名總是PRIMARY,就算自己命名了主鍵約束名也沒用。

  • 當建立主鍵約束時,系統預設會在所在的列或列組合上建立對應的主鍵索引(能夠根據主鍵查詢的,就根據主鍵查詢,效率更高)。如果刪除主鍵約束了,主鍵約束對應的索引就自動刪除了。

  • 需要注意的一點是,不要修改主鍵欄位的值。因為主鍵是資料記錄的唯一標識,如果修改了主鍵的值,就有可能會破壞資料的完整性。

4.4 新增主鍵約束

(1)建表時指定主鍵約束

create table 表名稱(
	欄位名  資料型別  primary key, #列級模式
    欄位名  資料型別,  
    欄位名  資料型別  
);
create table 表名稱(
	欄位名  資料型別,
    欄位名  資料型別,  
    欄位名  資料型別,
    [constraint 約束名] primary key(欄位名) #表級模式
);

舉例:

create table temp(
	id int primary key,
    name varchar(20)
);
mysql> desc temp;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
insert into temp values(1,'張三');#成功
insert into temp values(2,'李四');#成功
mysql> select * from temp;
+----+------+
| id | name |
+----+------+
|  1 | 張三 |
|  2 | 李四 |
+----+------+
2 rows in set (0.00 sec)
insert into temp values(1,'張三');#失敗
ERROR 1062 (23000): Duplicate(重複) entry(鍵入,輸入) '1' for key 'PRIMARY'


insert into temp values(1,'王五');#失敗
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

insert into temp values(3,'張三');#成功
mysql> select * from temp;
+----+------+
| id | name |
+----+------+
|  1 | 張三 |
|  2 | 李四 |
|  3 | 張三 |
+----+------+
3 rows in set (0.00 sec)
insert into temp values(4,null);#成功


insert into temp values(null,'李琦');#失敗
ERROR 1048 (23000): Column 'id' cannot be null
mysql> select * from temp;
+----+------+
| id | name |
+----+------+
|  1 | 張三 |
|  2 | 李四 |
|  3 | 張三 |
|  4 | NULL |
+----+------+
4 rows in set (0.00 sec)
#演示一個表建立兩個主鍵約束
create table temp(
	id int primary key,
    name varchar(20) primary key
);
ERROR 1068 (42000): Multiple(多重的) primary key defined(定義)

再舉例:

  • 列級約束

    CREATE TABLE emp4(
    id INT PRIMARY KEY AUTO_INCREMENT ,
    NAME VARCHAR(20)
    );
    
  • 表級約束

    CREATE TABLE emp5(
    id INT NOT NULL AUTO_INCREMENT,
    NAME VARCHAR(20),
    pwd VARCHAR(15),
    CONSTRAINT emp5_id_pk PRIMARY KEY(id)
    );
    

(2)建表後增加主鍵約束

ALTER TABLE 表名稱 ADD PRIMARY KEY(欄位列表); 
#欄位列表可以是一個欄位,也可以是多個欄位,如果是多個欄位的話,是複合主鍵
ALTER TABLE student ADD PRIMARY KEY (sid);
ALTER TABLE emp5 ADD PRIMARY KEY(NAME,pwd);

4.5 關於複合主鍵

create table 表名稱(
	欄位名  資料型別,
    欄位名  資料型別,  
    欄位名  資料型別,
    primary key(欄位名1,欄位名2)  #表示欄位1和欄位2的組合是唯一的,也可以有更多個欄位
);
#學生表
create table student(
	sid int primary key,  #學號
    sname varchar(20)     #學生姓名
);

#課程表
create table course(
	cid int primary key,  #課程編號
    cname varchar(20)     #課程名稱
);

#選課表
create table student_course(
	sid int,
    cid int,
    score int,
    primary key(sid,cid)  #複合主鍵
);
insert into student values(1,'張三'),(2,'李四');
insert into course values(1001,'Java'),(1002,'MySQL');
mysql> select * from student;
+-----+-------+
| sid | sname |
+-----+-------+
|   1 | 張三  |
|   2 | 李四  |
+-----+-------+
2 rows in set (0.00 sec)

mysql> select * from course;
+------+-------+
| cid  | cname |
+------+-------+
| 1001 | Java  |
| 1002 | MySQL |
+------+-------+
2 rows in set (0.00 sec)
insert into student_course values(1, 1001, 89),(1,1002,90),(2,1001,88),(2,1002,56);
mysql> select * from student_course;
+-----+------+-------+
| sid | cid  | score |
+-----+------+-------+
|   1 | 1001 |    89 |
|   1 | 1002 |    90 |
|   2 | 1001 |    88 |
|   2 | 1002 |    56 |
+-----+------+-------+
4 rows in set (0.00 sec)
insert into student_course values(1, 1001, 100);
ERROR 1062 (23000): Duplicate entry '1-1001' for key 'PRIMARY'
mysql> desc student_course;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| sid   | int(11) | NO   | PRI | NULL    |       |
| cid   | int(11) | NO   | PRI | NULL    |       |
| score | int(11) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
  • 再舉例
CREATE TABLE emp6(
id INT NOT NULL,
NAME VARCHAR(20),
pwd VARCHAR(15),
CONSTRAINT emp7_pk PRIMARY KEY(NAME,pwd)
);

4.6 刪除主鍵約束

alter table 表名稱 drop primary key;

舉例:

ALTER TABLE student DROP PRIMARY KEY;
ALTER TABLE emp5 DROP PRIMARY KEY;

說明:刪除主鍵約束,不需要指定主鍵名,因為一個表只有一個主鍵,刪除主鍵約束後,非空還存在。

5. 自增列:AUTO_INCREMENT

5.1 作用

某個欄位的值自增

5.2 關鍵字

auto_increment

5.3 特點和要求

(1)一個表最多隻能有一個自增長列

(2)當需要產生唯一識別符號或順序值時,可設定自增長

(3)自增長列約束的列必須是鍵列(主鍵列,唯一鍵列)

(4)自增約束的列的資料型別必須是整數型別

(5)如果自增列指定了 0 和 null,會在當前最大值的基礎上自增;如果自增列手動指定了具體值,直接賦值為具體值。

錯誤演示:

create table employee(
	eid int auto_increment,
    ename varchar(20)
);
 ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key   
create table employee(
	eid int primary key,
    ename varchar(20) unique key auto_increment
);
 ERROR 1063 (42000): Incorrect column specifier for column 'ename'  因為ename不是整數型別

5.4 如何指定自增約束

(1)建表時

create table 表名稱(
	欄位名  資料型別  primary key auto_increment,
    欄位名  資料型別  unique key not null,  
    欄位名  資料型別  unique key,
    欄位名  資料型別  not null default 預設值, 
);
create table 表名稱(
	欄位名  資料型別 default 預設值 ,
    欄位名  資料型別 unique key auto_increment,  
    欄位名  資料型別 not null default 預設值,,
    primary key(欄位名)
);
create table employee(
	eid int primary key auto_increment,
    ename varchar(20)
);
mysql> desc employee;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(11)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

(2)建表後

alter table 表名稱 modify 欄位名 資料型別 auto_increment;

例如:

create table employee(
	eid int primary key ,
    ename varchar(20)
);
alter table employee modify eid int auto_increment;
mysql> desc employee;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(11)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

5.5 如何刪除自增約束

#alter table 表名稱 modify 欄位名 資料型別 auto_increment;#給這個欄位增加自增約束

alter table 表名稱 modify 欄位名 資料型別; #去掉auto_increment相當於刪除
alter table employee modify eid int;
mysql> desc employee;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| eid   | int(11)     | NO   | PRI | NULL    |       |
| ename | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

5.6 MySQL 8.0新特性—自增變數的持久化

在MySQL 8.0之前,自增主鍵AUTO_INCREMENT的值如果大於max(primary key)+1,在MySQL重啟後,會重置AUTO_INCREMENT=max(primary key)+1,這種現象在某些情況下會導致業務主鍵衝突或者其他難以發現的問題。 下面通過案例來對比不同的版本中自增變數是否持久化。 在MySQL 5.7版本中,測試步驟如下: 建立的資料表中包含自增主鍵的id欄位,語句如下:

CREATE TABLE test1(
id INT PRIMARY KEY AUTO_INCREMENT
);

插入4個空值,執行如下:

INSERT INTO test1
VALUES(0),(0),(0),(0);

查詢資料表test1中的資料,結果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
4 rows in set (0.00 sec)

刪除id為4的記錄,語句如下:

DELETE FROM test1 WHERE id = 4;

再次插入一個空值,語句如下:

INSERT INTO test1 VALUES(0);

查詢此時資料表test1中的資料,結果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  5 |
+----+
4 rows in set (0.00 sec)

從結果可以看出,雖然刪除了id為4的記錄,但是再次插入空值時,並沒有重用被刪除的4,而是分配了5。 刪除id為5的記錄,結果如下:

DELETE FROM test1 where id=5;

重啟資料庫,重新插入一個空值。

INSERT INTO test1 values(0);

再次查詢資料表test1中的資料,結果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
4 rows in set (0.00 sec)

從結果可以看出,新插入的0值分配的是4,按照重啟前的操作邏輯,此處應該分配6。出現上述結果的主要原因是自增主鍵沒有持久化。

在MySQL 5.7系統中,對於自增主鍵的分配規則,是由InnoDB資料字典內部一個計數器來決定的,而該計數器只在記憶體中維護,並不會持久化到磁碟中。當資料庫重啟時,該計數器會被初始化。

在MySQL 8.0版本中,上述測試步驟最後一步的結果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
+----+
4 rows in set (0.00 sec)

從結果可以看出,自增變數已經持久化了。

MySQL 8.0將自增主鍵的計數器持久化到重做日誌中。每次計數器發生改變,都會將其寫入重做日誌中。如果資料庫重啟,InnoDB會根據重做日誌中的資訊來初始化計數器的記憶體值。

6. FOREIGN KEY 約束

6.1 作用

限定某個表的某個欄位的引用完整性。

比如:員工表的員工所在部門的選擇,必須在部門表能找到對應的部分。


6.2 關鍵字

FOREIGN KEY

6.3 主表和從表/父表和子表

主表(父表):被引用的表,被參考的表

從表(子表):引用別人的表,參考別人的表

例如:員工表的員工所在部門這個欄位的值要參考部門表:部門表是主表,員工表是從表。

例如:學生表、課程表、選課表:選課表的學生和課程要分別參考學生表和課程表,學生表和課程表是主表,選課表是從表。

6.4 特點

(1)從表的外來鍵列,必須引用/參考主表的主鍵或唯一約束的列

​ 為什麼?因為被依賴/被參考的值必須是唯一的

(2)在建立外來鍵約束時,如果不給外來鍵約束命名,預設名不是列名,而是自動產生一個外來鍵名(例如 student_ibfk_1;),也可以指定外來鍵約束名。

(3)建立(CREATE)表時就指定外來鍵約束的話,先建立主表,再建立從表

(4)刪表時,先刪從表(或先刪除外來鍵約束),再刪除主表

(5)當主表的記錄被從表參照時,主表的記錄將不允許刪除,如果要刪除資料,需要先刪除從表中依賴該記錄的資料,然後才可以刪除主表的資料

(6)在“從表”中指定外來鍵約束,並且一個表可以建立多個外來鍵約束

(7)從表的外來鍵列與主表被參照的列名字可以不相同,但是資料型別必須一樣,邏輯意義一致。如果型別不一樣,建立子表時,就會出現錯誤“ERROR 1005 (HY000): Can't create table'database.tablename'(errno: 150)”。

​ 例如:都是表示部門編號,都是int型別。

(8)當建立外來鍵約束時,系統預設會在所在的列上建立對應的普通索引。但是索引名是外來鍵的約束名。(根據外來鍵查詢效率很高)

(9)刪除外來鍵約束後,必須手動刪除對應的索引

6.5 新增外來鍵約束

(1)建表時

create table 主表名稱(
	欄位1  資料型別  primary key,
    欄位2  資料型別
);

create table 從表名稱(
	欄位1  資料型別  primary key,
    欄位2  資料型別,
    [CONSTRAINT <外來鍵約束名稱>] FOREIGN KEY(從表的某個欄位) references 主表名(被參考欄位)
);
#(從表的某個欄位)的資料型別必須與主表名(被參考欄位)的資料型別一致,邏輯意義也一樣
#(從表的某個欄位)的欄位名可以與主表名(被參考欄位)的欄位名一樣,也可以不一樣

-- FOREIGN KEY: 在表級指定子表中的列
-- REFERENCES: 標示在父表中的列
create table dept( #主表
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(#從表
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)   #在從表中指定外來鍵約束
    #emp表的deptid和和dept表的did的資料型別一致,意義都是表示部門的編號
);

說明:
(1)主表dept必須先建立成功,然後才能建立emp表,指定外來鍵成功。
(2)刪除表時,先刪除從表emp,再刪除主表dept

(2)建表後

一般情況下,表與表的關聯都是提前設計好了的,因此,會在建立表的時候就把外來鍵約束定義好。不過,如果需要修改表的設計(比如新增新的欄位,增加新的關聯關係),但沒有預先定義外來鍵約束,那麼,就要用修改表的方式來補充定義。

格式:

ALTER TABLE 從表名 ADD [CONSTRAINT 約束名] FOREIGN KEY (從表的欄位) REFERENCES 主表名(被引用欄位) [on update xx][on delete xx];

舉例:

ALTER TABLE emp1
ADD [CONSTRAINT emp_dept_id_fk] FOREIGN KEY(dept_id) REFERENCES dept(dept_id);

舉例:

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int				#員工所在的部門
);
#這兩個表建立時,沒有指定外來鍵的話,那麼建立順序是隨意
alter table emp add foreign key (deptid) references dept(did);

6.6 演示問題

(1)失敗:不是鍵列

create table dept(
	did int ,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)
);
#ERROR 1215 (HY000): Cannot add foreign key constraint  原因是dept的did不是鍵列

(2)失敗:資料型別不一致

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid char,				#員工所在的部門
    foreign key (deptid) references dept(did)
);
#ERROR 1215 (HY000): Cannot add foreign key constraint  原因是從表的deptid欄位和主表的did欄位的資料型別不一致,並且要它倆的邏輯意義一致

(3)成功,兩個表字段名一樣

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    did int,				#員工所在的部門
    foreign key (did) references dept(did)  
    #emp表的deptid和和dept表的did的資料型別一致,意義都是表示部門的編號
    #是否重名沒問題,因為兩個did在不同的表中
);

(4)新增、刪除、修改問題

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)  
    #emp表的deptid和和dept表的did的資料型別一致,意義都是表示部門的編號
);
insert into dept values(1001,'教學部');
insert into dept values(1003, '財務部');

insert into emp values(1,'張三',1001); #新增從表記錄成功,在新增這條記錄時,要求部門表有1001部門

insert into emp values(2,'李四',1005);#新增從表記錄失敗
ERROR 1452 (23000): Cannot add(新增) or update(修改) a child row: a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`)) 從表emp新增記錄失敗,因為主表dept沒有1005部門
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部  |
| 1003 | 財務部  |
+------+--------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三   |   1001 |
+-----+-------+--------+
1 row in set (0.00 sec)
update emp set deptid = 1002 where eid = 1;#修改從表失敗 
ERROR 1452 (23000): Cannot add(新增) or update(修改) a child row(子表的記錄): a foreign key constraint fails(外來鍵約束失敗) (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`))  #部門表did欄位現在沒有1002的值,所以員工表中不能修改員工所在部門deptid為1002

update dept set did = 1002 where did = 1001;#修改主表失敗
ERROR 1451 (23000): Cannot delete(刪除) or update(修改) a parent row(父表的記錄): a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`)) #部門表did的1001欄位已經被emp引用了,所以部門表的1001欄位就不能修改了。

update dept set did = 1002 where did = 1003;#修改主表成功  因為部門表的1003部門沒有被emp表引用,所以可以修改
delete from dept where did=1001; #刪除主表失敗
ERROR 1451 (23000): Cannot delete(刪除) or update(修改) a parent row(父表記錄): a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`))  #因為部門表did的1001欄位已經被emp引用了,所以部門表的1001欄位對應的記錄就不能被刪除

總結:約束關係是針對雙方的

  • 添加了外來鍵約束後,主表的修改和刪除資料受約束

  • 添加了外來鍵約束後,從表的新增和修改資料受約束

  • 在從表上建立外來鍵,要求主表必須存在

  • 刪除主表時,要求從表從表先刪除,或將從表中外來鍵引用該主表的關係先刪除

6.7 約束等級

  • Cascade方式:在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄

  • Set null方式:在父表上update/delete記錄時,將子表上匹配記錄的列設為null,但是要注意子表的外來鍵列不能為not null

  • No action方式:如果子表中有匹配的記錄,則不允許對父表對應候選鍵進行update/delete操作

  • Restrict方式:同no action, 都是立即檢查外來鍵約束

  • Set default方式(在視覺化工具SQLyog中可能顯示空白):父表有變更時,子表將外來鍵列設定成一個預設的值,但Innodb不能識別

如果沒有指定等級,就相當於Restrict方式。

對於外來鍵約束,最好是採用: ON UPDATE CASCADE ON DELETE RESTRICT 的方式。

(1)演示1:on update cascade on delete set null

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)  on update cascade on delete set null
    #把修改操作設定為級聯修改等級,把刪除操作設定為set null等級
);
insert into dept values(1001,'教學部');
insert into dept values(1002, '財務部');
insert into dept values(1003, '諮詢部');

insert into emp values(1,'張三',1001); #在新增這條記錄時,要求部門表有1001部門
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);

#修改主表成功,從表也跟著修改,修改了主表被引用的欄位1002為1004,從表的引用欄位就跟著修改為1004了
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1003 | 諮詢部 |
| 1004 | 財務部 | #原來是1002,修改為1004
+------+--------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1004 | #原來是1002,跟著修改為1004
+-----+-------+--------+
3 rows in set (0.00 sec)
#刪除主表的記錄成功,從表對應的欄位的值被修改為null
mysql> delete from dept where did = 1001;
Query OK, 1 row affected (0.01 sec)

mysql> select * from dept;
+------+--------+
| did  | dname  | #記錄1001部門被刪除了
+------+--------+
| 1003 | 諮詢部  |
| 1004 | 財務部  |
+------+--------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   NULL | #原來引用1001部門的員工,deptid欄位變為null
|   2 | 李四  |   NULL |
|   3 | 王五  |   1004 |
+-----+-------+--------+
3 rows in set (0.00 sec)

(2)演示2:on update set null on delete cascade

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)  on update set null on delete cascade
    #把修改操作設定為set null等級,把刪除操作設定為級聯刪除等級
);
insert into dept values(1001,'教學部');
insert into dept values(1002, '財務部');
insert into dept values(1003, '諮詢部');

insert into emp values(1,'張三',1001); #在新增這條記錄時,要求部門表有1001部門
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1002 | 財務部 |
| 1003 | 諮詢部 |
+------+--------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1002 |
+-----+-------+--------+
3 rows in set (0.00 sec)
#修改主表,從表對應的欄位設定為null
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1003 | 諮詢部 |
| 1004 | 財務部 | #原來did是1002
+------+--------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   NULL | #原來deptid是1002,因為部門表1002被修改了,1002沒有對應的了,就設定為null
+-----+-------+--------+
3 rows in set (0.00 sec)
#刪除主表的記錄成功,主表的1001行被刪除了,從表相應的記錄也被刪除了
mysql> delete from dept where did=1001;
Query OK, 1 row affected (0.00 sec)

mysql> select * from dept;
+------+--------+
| did  | dname  | #部門表中1001部門被刪除
+------+--------+
| 1003 | 諮詢部 |
| 1004 | 財務部 |
+------+--------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |#原來1001部門的員工也被刪除了
+-----+-------+--------+
|   3 | 王五  |   NULL |
+-----+-------+--------+
1 row in set (0.00 sec)

(3)演示:on update cascade on delete cascade

create table dept(
	did int primary key,		#部門編號
    dname varchar(50)			#部門名稱
);

create table emp(
	eid int primary key,  #員工編號
    ename varchar(5),     #員工姓名
    deptid int,				#員工所在的部門
    foreign key (deptid) references dept(did)  on update cascade on delete cascade
    #把修改操作設定為級聯修改等級,把刪除操作也設定為級聯刪除等級
);
insert into dept values(1001,'教學部');
insert into dept values(1002, '財務部');
insert into dept values(1003, '諮詢部');

insert into emp values(1,'張三',1001); #在新增這條記錄時,要求部門表有1001部門
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1002 | 財務部 |
| 1003 | 諮詢部 |
+------+--------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1002 |
+-----+-------+--------+
3 rows in set (0.00 sec)
#修改主表,從表對應的欄位自動修改
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1003 | 諮詢部 |
| 1004 | 財務部 | #部門1002修改為1004
+------+--------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1004 | #級聯修改
+-----+-------+--------+
3 rows in set (0.00 sec)
#刪除主表的記錄成功,主表的1001行被刪除了,從表相應的記錄也被刪除了
mysql> delete from dept where did=1001;
Query OK, 1 row affected (0.00 sec)

mysql> select * from dept;
+------+--------+
| did  | dname  | #1001部門被刪除了
+------+--------+
| 1003 | 諮詢部 |
| 1004 | 財務部 | 
+------+--------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |  #1001部門的員工也被刪除了
+-----+-------+--------+
|   3 | 王五  |   1004 |
+-----+-------+--------+
1 row in set (0.00 sec)

6.8 刪除外來鍵約束

流程如下:

(1)第一步先檢視約束名和刪除外來鍵約束
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名稱';#檢視某個表的約束名

ALTER TABLE 從表名 DROP FOREIGN KEY 外來鍵約束名;

(2)第二步檢視索引名和刪除索引。(注意,只能手動刪除)
SHOW INDEX FROM 表名稱; #檢視某個表的索引名

ALTER TABLE 從表名 DROP INDEX 索引名;

舉例:

mysql> SELECT * FROM information_schema.table_constraints WHERE table_name = 'emp';

mysql> alter table emp drop foreign key emp_ibfk_1;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from emp;

mysql> alter table emp drop index deptid;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>  show index from emp;

6.9 開發場景

問題1:如果兩個表之間有關係(一對一、一對多),比如:員工表和部門表(一對多),它們之間是否一定要建外來鍵約束?

答:不是的

問題2:建和不建外來鍵約束有什麼區別?

答:建外來鍵約束,你的操作(建立表、刪除表、新增、修改、刪除)會受到限制,從語法層面受到限制。例如:在員工表中不可能新增一個員工資訊,它的部門的值在部門表中找不到。

不建外來鍵約束,你的操作(建立表、刪除表、新增、修改、刪除)不受限制,要保證資料的引用完整性,只能依靠程式設計師的自覺,或者是在Java程式中進行限定。例如:在員工表中,可以新增一個員工的資訊,它的部門指定為一個完全不存在的部門。

問題3:那麼建和不建外來鍵約束和查詢有沒有關係?

答:沒有

在 MySQL 裡,外來鍵約束是有成本的,需要消耗系統資源。對於大併發的 SQL 操作,有可能會不適合。比如大型網站的中央資料庫,可能會因為外來鍵約束的系統開銷而變得非常慢。所以, MySQL 允許你不使用系統自帶的外來鍵約束,在應用層面完成檢查資料一致性的邏輯。也就是說,即使你不用外來鍵約束,也要想辦法通過應用層面的附加邏輯,來實現外來鍵約束的功能,確保資料的一致性。

6.10 阿里開發規範

強制】不得使用外來鍵與級聯,一切外來鍵概念必須在應用層解決。

說明:(概念解釋)學生表中的 student_id 是主鍵,那麼成績表中的 student_id 則為外來鍵。如果更新學生表中的 student_id,同時觸發成績表中的 student_id 更新,即為級聯更新。外來鍵與級聯更新適用於單機低併發,不適合分散式高併發叢集;級聯更新是強阻塞,存在資料庫更新風暴的風險;外來鍵影響資料庫的插入速度

7. CHECK 約束

7.1 作用

檢查某個欄位的值是否符號xx要求,一般指的是值的範圍

2、關鍵字

CHECK

3、說明:MySQL 5.7 不支援

MySQL5.7 可以使用check約束,但check約束對資料驗證沒有任何作用。新增資料時,沒有任何錯誤或警告

但是MySQL 8.0中可以使用check約束了

create table employee(
	eid int primary key,
    ename varchar(5),
    gender char check ('男' or '女')
);
insert into employee values(1,'張三','妖');
mysql> select * from employee;
+-----+-------+--------+
| eid | ename | gender |
+-----+-------+--------+
|   1 | 張三   | 妖     |
+-----+-------+--------+
1 row in set (0.00 sec)
  • 再舉例
CREATE TABLE temp(
id INT AUTO_INCREMENT,
NAME VARCHAR(20),
age INT CHECK(age > 20),
PRIMARY KEY(id)
);
  • 再舉例
age tinyint check(age >20) 或 sex char(2) check(sex in(‘男’,’女’))
  • 再舉例
CHECK(height>=0 AND height<3)

8. DEFAULT約束

8.1 作用

給某個欄位/某列指定預設值,一旦設定預設值,在插入資料時,如果此欄位沒有顯式賦值,則賦值為預設值。

8.2 關鍵字

DEFAULT

8.3 如何給欄位加預設值

(1)建表時

create table 表名稱(
	欄位名  資料型別  primary key,
    欄位名  資料型別  unique key not null,  
    欄位名  資料型別  unique key,
    欄位名  資料型別  not null default 預設值, 
);
create table 表名稱(
	欄位名  資料型別 default 預設值 ,
    欄位名  資料型別 not null default 預設值,  
    欄位名  資料型別 not null default 預設值,
    primary key(欄位名),
    unique key(欄位名)
);

說明:預設值約束一般不在唯一鍵和主鍵列上加
create table employee(
	eid int primary key,
    ename varchar(20) not null,
    gender char default '男',
    tel char(11) not null default '' #預設是空字串
);
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | NO   |     | NULL    |       |
| gender | char(1)     | YES  |     | 男      |       |
| tel    | char(11)    | NO   |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
insert into employee values(1,'汪飛','男','13700102535'); #成功
mysql> select * from employee;
+-----+-------+--------+-------------+
| eid | ename | gender | tel         |
+-----+-------+--------+-------------+
|   1 | 汪飛  | 男     | 13700102535 |
+-----+-------+--------+-------------+
1 row in set (0.00 sec)
insert into employee(eid,ename) values(2,'天琪'); #成功
mysql> select * from employee;
+-----+-------+--------+-------------+
| eid | ename | gender | tel         |
+-----+-------+--------+-------------+
|   1 | 汪飛  | 男     | 13700102535 |
|   2 | 天琪  | 男     |             |
+-----+-------+--------+-------------+
2 rows in set (0.00 sec)
insert into employee(eid,ename) values(3,'二虎');
#ERROR 1062 (23000): Duplicate entry '' for key 'tel'  
#如果tel有唯一性約束的話會報錯,如果tel沒有唯一性約束,可以新增成功

再舉例:

CREATE TABLE myemp(
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(15),
salary DOUBLE(10,2) DEFAULT 2000
);

(2)建表後

alter table 表名稱 modify 欄位名 資料型別 default 預設值;

#如果這個欄位原來有非空約束,你還保留非空約束,那麼在加預設值約束時,還得保留非空約束,否則非空約束就被刪除了
#同理,在給某個欄位加非空約束也一樣,如果這個欄位原來有預設值約束,你想保留,也要在modify語句中保留預設值約束,否則就刪除了
alter table 表名稱 modify 欄位名 資料型別 default 預設值 not null;
create table employee(
	eid int primary key,
    ename varchar(20),
    gender char,
    tel char(11) not null
);
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | NULL    |       |
| tel    | char(11)    | NO   |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
alter table employee modify gender char default '男';  #給gender欄位增加預設值約束
alter table employee modify tel char(11) default ''; #給tel欄位增加預設值約束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | 男      |       |
| tel    | char(11)    | YES  |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
alter table employee modify tel char(11) default ''  not null;#給tel欄位增加預設值約束,並保留非空約束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | 男      |       |
| tel    | char(11)    | NO   |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

8.4 如何刪除預設值約束

alter table 表名稱 modify 欄位名 資料型別 ;#刪除預設值約束,也不保留非空約束

alter table 表名稱 modify 欄位名 資料型別  not null; #刪除預設值約束,保留非空約束
alter table employee modify gender char; #刪除gender欄位預設值約束,如果有非空約束,也一併刪除
alter table employee modify tel char(11)  not null;#刪除tel欄位預設值約束,保留非空約束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | NULL    |       |
| tel    | char(11)    | NO   |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

9. 面試

面試1、為什麼建表時,加 not null default '' 或 default 0

答:不想讓表中出現null值。

面試2、為什麼不想要 null 的值

答:(1)不好比較。null是一種特殊值,比較時只能用專門的is null 和 is not null來比較。碰到運算子,通常返回null。

​ (2)效率不高。影響提高索引效果。因此,我們往往在建表時 not null default '' 或 default 0

面試3、帶AUTO_INCREMENT約束的欄位值是從1開始的嗎?

在MySQL中,預設AUTO_INCREMENT的初始值是1,每新增一條記錄,欄位值自動加1。設定自增屬性(AUTO_INCREMENT)的時候,還可以指定第一條插入記錄的自增欄位的值,這樣新插入的記錄的自增欄位值從初始值開始遞增,如在表中插入第一條記錄,同時指定id值為5,則以後插入的記錄的id值就會從6開始往上增加。新增主鍵約束時,往往需要設定欄位自動增加屬性。

面試4、並不是每個表都可以任意選擇儲存引擎?

外來鍵約束(FOREIGN KEY)不能跨引擎使用。

MySQL支援多種儲存引擎,每一個表都可以指定一個不同的儲存引擎,需要注意的是:外來鍵約束是用來保證資料的參照完整性的,如果表之間需要關聯外來鍵,卻指定了不同的儲存引擎,那麼這些表之間是不能建立外來鍵約束的。所以說,儲存引擎的選擇也不完全是隨意的。