九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
MySQL: MySQL約束(詳細、全)


1. 約束(constraint)概述

1.1 為什么需要約束

數(shù)據(jù)完整性(Data Integrity)是指數(shù)據(jù)的精確性(Accuracy)和可靠性(Reliability)。它是防止數(shù)據(jù)庫中存在不符合語義規(guī)定的數(shù)據(jù)和防止因錯誤信息的輸入輸出造成無效操作或錯誤信息而提出的。

為了保證數(shù)據(jù)的完整性,SQL規(guī)范以約束的方式對 表數(shù)據(jù)進行額外的條件限制。從以下四個方面考慮:

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

1.2 什么是約束

約束是表級的強制規(guī)定。

可以在創(chuàng)建表時規(guī)定約束(通過 CREATE TABLE 語句),或者在表創(chuàng)建之后通過 ALTER TABLE 語句規(guī)定約束。

1.3 約束的分類

  • 根據(jù)約束數(shù)據(jù)列的限制, 約束可分為:
    • 單列約束:每個約束只約束一列
    • 多列約束:每個約束可約束多列數(shù)據(jù)
  • 根據(jù)約束的作用范圍,約束可分為:
    • 列級約束:只能作用在一個列上,跟在列的定義后面
    • 表級約束:在表中所有字段都聲明完, 在所有字段的后面聲明的約束
			位置			支持的約束類型					是否可以起約束名
列級約束:	列的后面		語法都支持,但外鍵沒有效果			不可以
表級約束:	所有列的下面	   默認和非空不支持,其他支持	   可以(主鍵沒有效果)
  • 根據(jù)約束起的作用,約束可分為:
    • NOT NULL 非空約束,規(guī)定某個字段不能為空
    • UNIQUE 唯一約束,規(guī)定某個字段在整個表中是唯一的
    • PRIMARY KEY 主鍵(非空且唯一)約束
    • FOREIGN KEY 外鍵約束
    • CHECK 檢查約束
    • DEFAULT 默認值約束

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

  • 查看某個表已有的約束
#information_schema數(shù)據(jù)庫名(系統(tǒng)庫)
#table_constraints表名稱(專門存儲各個表的約束)
SELECT * FROM information_schema.table_constraints 
WHERE table_name = '表名稱';

2. 非空約束 (重要)

2.1 作用

限定某個字段/某列的值不允許為空

2.2 關鍵字

NOT NULL

2.3 特點

  • 默認,所有的類型的值都可以是NULL,包括INT、FLOAT等數(shù)據(jù)類型
  • 非空約束只能出現(xiàn)在表對象的列上,只能某個列單獨限定非空,不能組合非空
  • 一個表可以有很多列都分別限定了非空
  • 空字符串’'不等于NULL,0也不等于NULL

2.4 添加非空約束

(1)建表時

CREATE TABLE 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型 NOT NULL,  
    字段名  數(shù)據(jù)類型 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 字段名 數(shù)據(jù)類型 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 字段名 數(shù)據(jù)類型 NULL;#去掉not null,相當于修改某個非注解字段,該字段允許為空

或 

alter table 表名稱 modify 字段名 數(shù)據(jù)類型;#去掉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 特點

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

3.4 添加唯一約束

(1)建表時

create table 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型  unique,  # unique key 也行,一個意思
    字段名  數(shù)據(jù)類型  unique key, # 列級約束
    字段名  數(shù)據(jù)類型
);
create table 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型,  
    字段名  數(shù)據(jù)類型,
    [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');
sql> 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 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型,  
    字段名  數(shù)據(jù)類型,
    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');#成功
sql> select * from student;
+-----+-------+-------------+--------------------+
| sid | sname | tel         | cardid             |
+-----+-------+-------------+--------------------+
|   1 | 張三  | 13710011002 | 101223199012015623 |
|   2 | 李四  | 13710011003 | 101223199012015624 |
+-----+-------+-------------+--------------------+
2 rows in set (0.00 sec)

sql> 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);#成功
sql> 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 刪除唯一約束

  • 添加唯一性約束的列上也會自動創(chuàng)建唯一索引。
  • 刪除唯一約束只能通過刪除唯一索引的方式刪除。
  • 刪除時需要指定唯一索引名,唯一索引名就和唯一約束名一樣。
  • 如果創(chuàng)建唯一約束時未指定名稱,如果是單列,就默認和列名相同;如果是組合列,那么默認和()中排在第一個的列名相同。也可以自定義唯一性約束名。
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 特點

  • 主鍵約束相當于唯一約束+非空約束的組合,主鍵約束列不允許重復,也不允許出現(xiàn)空值。

  • 一個表最多只能有一個主鍵約束,建立主鍵約束可以在列級別創(chuàng)建,也可以在表級別上創(chuàng)建。

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

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

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

  • 當創(chuàng)建主鍵約束時,系統(tǒng)默認會在所在的列或列組合上建立對應的主鍵索引(能夠根據(jù)主鍵查詢的,就根據(jù)主鍵查詢,效率更高)。如果刪除主鍵約束了,主鍵約束對應的索引就自動刪除了。

  • 需要注意的一點是,不要修改主鍵字段的值。因為主鍵是數(shù)據(jù)記錄的唯一標識,如果修改了主鍵的值,就有可能會破壞數(shù)據(jù)的完整性。

4.4 添加主鍵約束

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

create table 表名稱(
	字段名  數(shù)據(jù)類型  primary key, #列級模式
    字段名  數(shù)據(jù)類型,  
    字段名  數(shù)據(jù)類型  
);
create table 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型,  
    字段名  數(shù)據(jù)類型,
    [constraint 約束名] primary key(字段名) #表級模式
);

舉例:

create table temp(
	id int primary key,
    name varchar(20)
);
sql> 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,'李四');#成功
sql> 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,'張三');#成功
sql> 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
sql> 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 表名稱(
	字段名  數(shù)據(jù)類型,
    字段名  數(shù)據(jù)類型,  
    字段名  數(shù)據(jù)類型,
    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');
sql> select * from student;
+-----+-------+
| sid | sname |
+-----+-------+
|   1 | 張三  |
|   2 | 李四  |
+-----+-------+
2 rows in set (0.00 sec)

sql> 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);
sql> 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'
sql> 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 作用

某個字段的值自增

開發(fā)中, 如果主鍵設置了自增, 一般我們寫sql的時候, 就不用在寫主鍵列了

5.2 關鍵字

auto_increment

5.3 特點和要求

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

(2)當需要產(chǎn)生唯一標識符或順序值時,可設置自增長

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

(4)自增約束的列的數(shù)據(jù)類型必須是整數(shù)類型

(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不是整數(shù)類型

5.4 如何指定自增約束

(1)建表時

create table 表名稱(
	字段名  數(shù)據(jù)類型  primary key auto_increment,
    字段名  數(shù)據(jù)類型  unique key not null,  
    字段名  數(shù)據(jù)類型  unique key,
    字段名  數(shù)據(jù)類型  not null default 默認值, 
);
create table 表名稱(
	字段名  數(shù)據(jù)類型 default 默認值 ,
    字段名  數(shù)據(jù)類型 unique key auto_increment,  
    字段名  數(shù)據(jù)類型 not null default 默認值,,
    primary key(字段名)
);
create table employee(
	eid int primary key auto_increment,
    ename varchar(20)
);
sql> 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 字段名 數(shù)據(jù)類型 auto_increment;

例如:

create table employee(
	eid int primary key ,
    ename varchar(20)
);
alter table employee modify eid int auto_increment;
sql> 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 字段名 數(shù)據(jù)類型 auto_increment;#給這個字段增加自增約束

alter table 表名稱 modify 字段名 數(shù)據(jù)類型; #去掉auto_increment相當于刪除
alter table employee modify eid int;
sql> 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,這種現(xiàn)象在某些情況下會導致業(yè)務主鍵沖突或者其他難以發(fā)現(xiàn)的問題。

下面通過案例來對比不同的版本中自增變量是否持久化。
在MySQL 5.7版本中,測試步驟如下:
創(chuàng)建的數(shù)據(jù)表中包含自增主鍵的id字段,語句如下:

CREATE TABLE test1(
	id INT PRIMARY KEY AUTO_INCREMENT
);

插入4個空值,執(zhí)行如下:

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

查詢數(shù)據(jù)表test1中的數(shù)據(jù),結(jié)果如下:

sql> 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);

查詢此時數(shù)據(jù)表test1中的數(shù)據(jù),結(jié)果如下:

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

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

DELETE FROM test1 where id=5;

重啟數(shù)據(jù)庫,重新插入一個空值。

INSERT INTO test1 values(0);

再次查詢數(shù)據(jù)表test1中的數(shù)據(jù),結(jié)果如下:

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

從結(jié)果可以看出,新插入的0值分配的是4,按照重啟前的操作邏輯,此處應該分配6。出現(xiàn)上述結(jié)果的主要原因是自增主鍵沒有持久化。
在MySQL 5.7系統(tǒng)中,對于自增主鍵的分配規(guī)則,是由InnoDB數(shù)據(jù)字典內(nèi)部一個計數(shù)器來決定的,而該計數(shù)器只在內(nèi)存中維護,并不會持久化到磁盤中。當數(shù)據(jù)庫重啟時,該計數(shù)器會被初始化。

在MySQL 8.0版本中,上述測試步驟最后一步的結(jié)果如下:

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

從結(jié)果可以看出,自增變量已經(jīng)持久化了。

MySQL 8.0將自增主鍵的計數(shù)器持久化到重做日志中。每次計數(shù)器發(fā)生改變,都會將其寫入重做日志中。如果數(shù)據(jù)庫重啟,InnoDB會根據(jù)重做日志中的信息來初始化計數(shù)器的內(nèi)存值。

6. FOREIGN KEY 約束 (了解,開發(fā)不建議使用)

6.1 作用

限定某個表的某個字段的引用完整性。

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

下圖: 員工表就是從表; 部門表是主表

6.2 關鍵字

FOREIGN KEY

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

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

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

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

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

6.4 特點

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

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

(2)在創(chuàng)建外鍵約束時,如果不給外鍵約束命名,默認名不是列名,而是自動產(chǎn)生一個外鍵名(例如 student_ibfk_1;),也可以指定外鍵約束名。

(3)創(chuàng)建(CREATE)表時就指定外鍵約束的話,先創(chuàng)建主表,再創(chuàng)建從表;

(4)刪表時,先刪從表(或先刪除外鍵約束),再刪除主表; (因為從表引用著主表的主鍵, 如果先刪主表就會報錯, 因為從表還引用著主表的主鍵)

(5)當主表的記錄被從表參照時,主表的記錄將不允許刪除,如果要刪除數(shù)據(jù),需要先刪除從表中依賴該記錄的數(shù)據(jù),然后才可以刪除主表的數(shù)據(jù)

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

(7)從表的外鍵列與主表被參照的列名字可以不相同,但是數(shù)據(jù)類型必須一樣,邏輯意義一致。如果類型不一樣,創(chuàng)建子表時,就會出現(xiàn)錯誤“ERROR 1005 (HY000): Can’t create table’database.tablename’(errno: 150)”。

? 例如:都是表示部門編號,都是int類型。

(8)當創(chuàng)建外鍵約束時,系統(tǒng)默認會在所在的列上建立對應的普通索引。但是索引名是外鍵的約束名。(根據(jù)外鍵查詢效率很高)

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

6.5 添加外鍵約束

(1)建表時

create table 主表名稱(
	字段1  數(shù)據(jù)類型  primary key,
    字段2  數(shù)據(jù)類型
);

create table 從表名稱(
	字段1  數(shù)據(jù)類型  primary key,
    字段2  數(shù)據(jù)類型,
    [CONSTRAINT <外鍵約束名稱>] FOREIGN KEY(從表的某個字段) references 主表名(被參考字段)
);
#(從表的某個字段)的數(shù)據(jù)類型必須與主表名(被參考字段)的數(shù)據(jù)類型一致,邏輯意義也一樣
#(從表的某個字段)的字段名可以與主表名(被參考字段)的字段名一樣,也可以不一樣

-- 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的數(shù)據(jù)類型一致,意義都是表示部門的編號
);

說明:
(1)主表dept必須先創(chuàng)建成功,然后才能創(chuàng)建emp表,指定外鍵成功。
(2)刪除表時,先刪除從表emp,再刪除主表dept

(2)建表后

一般情況下,表與表的關聯(lián)都是提前設計好了的,因此,會在創(chuàng)建表的時候就把外鍵約束定義好。不過,如果需要修改表的設計(比如添加新的字段,增加新的關聯(lián)關系),但沒有預先定義外鍵約束,那么,就要用修改表的方式來補充定義。

格式:

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				#員工所在的部門
);
#這兩個表創(chuàng)建時,沒有指定外鍵的話,那么創(chuàng)建順序是隨意
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)失?。簲?shù)據(jù)類型不一致

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字段的數(shù)據(jù)類型不一致,并且要它倆的邏輯意義一致

(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的數(shù)據(jù)類型一致,意義都是表示部門的編號
    #是否重名沒問題,因為兩個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的數(shù)據(jù)類型一致,意義都是表示部門的編號
);
insert into dept values(1001,'教學部');
insert into dept values(1003, '財務部');

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

insert into emp values(2,'李四',1005);#添加從表記錄失敗, 主表中沒有1055號部門

-- 從表emp添加記錄失敗,因為主表dept沒有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`)) 
sql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部  |
| 1003 | 財務部  |
+------+--------+
2 rows in set (0.00 sec)

sql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三   |   1001 |
+-----+-------+--------+
1 row in set (0.00 sec)
update emp set deptid = 1002 where eid = 1;#修改從表失敗 
#部門表did字段現(xiàn)在沒有1002的值,所以員工表中不能修改員工所在部門deptid為1002
--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`)) 

update dept set did = 1002 where did = 1001;#修改主表失敗
#部門表did的1001字段已經(jīng)被emp引用了,所以部門表的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`))

#修改主表成功  因為部門表的1003部門沒有被emp表引用,所以可以修改
update dept set did = 1002 where did = 1003;
delete from dept where did=1001; #刪除主表失敗

#因為部門表did的1001字段已經(jīng)被emp引用了,所以部門表的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`))

總結(jié):約束關系是針對雙方的

  • 添加了外鍵約束后,主表的修改和刪除數(shù)據(jù)受約束
  • 添加了外鍵約束后,從表的添加和修改數(shù)據(jù)受約束
  • 在從表上建立外鍵,要求主表必須存在
  • 刪除主表時,要求從表從表先刪除,或?qū)谋碇型怄I引用該主表的關系先刪除

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
    #把修改操作設置為級聯(lián)修改等級,把刪除操作設置為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);

sql> select * from dept;

sql> select * from emp;

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

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

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

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

sql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 張三  |   NULL | #原來引用1001部門的員工,deptid字段變?yōu)閚ull
|   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等級,把刪除操作設置為級聯(lián)刪除等級
);
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);
sql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1002 | 財務部 |
| 1003 | 咨詢部 |
+------+--------+
3 rows in set (0.00 sec)

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

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

sql> 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行被刪除了,從表相應的記錄也被刪除了
sql> delete from dept where did=1001;
Query OK, 1 row affected (0.00 sec)

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

sql> 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
    #把修改操作設置為級聯(lián)修改等級,把刪除操作也設置為級聯(lián)刪除等級
);
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);
sql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教學部 |
| 1002 | 財務部 |
| 1003 | 咨詢部 |
+------+--------+
3 rows in set (0.00 sec)

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

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

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

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

sql> 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 索引名;

舉例:

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

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

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

sql>  show index from emp;

6.9 開發(fā)場景

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

答:不是的

問題2:建和不建外鍵約束有什么區(qū)別?

答:建外鍵約束,你的操作(創(chuàng)建表、刪除表、添加、修改、刪除)會受到限制,從語法層面受到限制。例如:在員工表中不可能添加一個員工信息,它的部門的值在部門表中找不到。

不建外鍵約束,你的操作(創(chuàng)建表、刪除表、添加、修改、刪除)不受限制,要保證數(shù)據(jù)的引用完整性,只能依靠程序員的自覺,或者是在Java程序中進行限定。例如:在員工表中,可以添加一個員工的信息,它的部門指定為一個完全不存在的部門。

問題3:那么建和不建外鍵約束和查詢有沒有關系?

答:沒有

在 MySQL 里,外鍵約束是有成本的,需要消耗系統(tǒng)資源。對于大并發(fā)的 SQL 操作,有可能會不適合。比如大型網(wǎng)站的中央數(shù)據(jù)庫,可能會因為外鍵約束的系統(tǒng)開銷而變得非常慢。所以, MySQL 允許你不使用系統(tǒng)自帶的外鍵約束,在應用層面完成檢查數(shù)據(jù)一致性的邏輯。也就是說,即使你不用外鍵約束,也要想辦法通過應用層面的附加邏輯,來實現(xiàn)外鍵約束的功能,確保數(shù)據(jù)的一致性。

6.10 阿里開發(fā)規(guī)范

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

說明:(概念解釋)學生表中的 student_id 是主鍵,那么成績表中的 student_id 則為外鍵。如果更新學生表中的 student_id,同時觸發(fā)成績表中的 student_id 更新,即為級聯(lián)更新。外鍵與級聯(lián)更新適用于單機低并發(fā),不適合分布式、高并發(fā)集群;級聯(lián)更新是強阻塞,存在數(shù)據(jù)庫更新風暴的風險;外鍵影響數(shù)據(jù)庫的插入速度。

7. CHECK 約束

7.1 作用

檢查某個字段的值是否符號xx要求,一般指的是值的范圍

2、關鍵字

CHECK

3、說明:MySQL 5.7 不支持

在Oracle中是支持的

MySQL5.7 可以使用check約束,但check約束對數(shù)據(jù)驗證沒有任何作用。添加數(shù)據(jù)時,沒有任何錯誤或警告

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

create table employee(
	eid int primary key,
    ename varchar(5),
    gender char check ('男' or '女')
);
insert into employee values(1,'張三','妖');
sql> 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 作用

給某個字段/某列指定默認值,一旦設置默認值,在插入數(shù)據(jù)時,如果此字段沒有顯式賦值,則賦值為默認值。

8.2 關鍵字

DEFAULT

8.3 如何給字段加默認值

(1)建表時

create table 表名稱(
	字段名  數(shù)據(jù)類型  primary key,
    字段名  數(shù)據(jù)類型  unique key not null,  
    字段名  數(shù)據(jù)類型  unique key,
    字段名  數(shù)據(jù)類型  not null default 默認值, 
);
create table 表名稱(
	字段名  數(shù)據(jù)類型 default 默認值 ,
    字段名  數(shù)據(jù)類型 not null default 默認值,  
    字段名  數(shù)據(jù)類型 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 '' #默認是空字符串
);
sql> 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'); #成功
sql> select * from employee;
+-----+-------+--------+-------------+
| eid | ename | gender | tel         |
+-----+-------+--------+-------------+
|   1 | 汪飛  | 男     | 13700102535 |
+-----+-------+--------+-------------+
1 row in set (0.00 sec)
insert into employee(eid,ename) values(2,'天琪'); #成功
sql> 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 字段名 數(shù)據(jù)類型 default 默認值;

#如果這個字段原來有非空約束,你還保留非空約束,那么在加默認值約束時,還得保留非空約束,否則非空約束就被刪除了
#同理,在給某個字段加非空約束也一樣,如果這個字段原來有默認值約束,你想保留,也要在modify語句中保留默認值約束,否則就刪除了
alter table 表名稱 modify 字段名 數(shù)據(jù)類型 default 默認值 not null;
create table employee(
	eid int primary key,
    ename varchar(20),
    gender char,
    tel char(11) not null
);
sql> 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字段增加默認值約束
sql> 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字段增加默認值約束,并保留非空約束
sql> 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 字段名 數(shù)據(jù)類型 ;#刪除默認值約束,也不保留非空約束

alter table 表名稱 modify 字段名 數(shù)據(jù)類型  not null; #刪除默認值約束,保留非空約束
alter table employee modify gender char; #刪除gender字段默認值約束,如果有非空約束,也一并刪除
alter table employee modify tel char(11)  not null;#刪除tel字段默認值約束,保留非空約束
sql> 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

答:不想讓表中出現(xiàn)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支持多種存儲引擎,每一個表都可以指定一個不同的存儲引擎,需要注意的是:外鍵約束是用來保證數(shù)據(jù)的參照完整性的,如果表之間需要關聯(lián)外鍵,卻指定了不同的存儲引擎,那么這些表之間是不能創(chuàng)建外鍵約束的。所以說,存儲引擎的選擇也不完全是隨意的。

練習題

#第13章_約束的課后練習

#練習1:
CREATE DATABASE test04_emp;

USE test04_emp;

CREATE TABLE emp2(
id INT,
emp_name VARCHAR(15)
);

CREATE TABLE dept2(
id INT,
dept_name VARCHAR(15)
);

#1.向表emp2的id列中添加PRIMARY KEY約束

ALTER TABLE emp2
ADD CONSTRAINT pk_emp2_id PRIMARY KEY(id);


#2.向表dept2的id列中添加PRIMARY KEY約束

ALTER TABLE dept2
ADD PRIMARY KEY(id);


#3.向表emp2中添加列dept_id,并在其中定義FOREIGN KEY約束,與之相關聯(lián)的列是dept2表中的id列。

ALTER TABLE emp2
ADD dept_id INT;

DESC emp2;

ALTER TABLE emp2
ADD CONSTRAINT fk_emp2_deptid FOREIGN KEY(dept_id) REFERENCES dept2(id);

#練習2:
#承接《第11章_數(shù)據(jù)處理之增刪改》的綜合案例。
USE test01_library;

DESC books;

#根據(jù)題目要求給books表中的字段添加約束
#方式1:
ALTER TABLE books
ADD PRIMARY KEY (id);

ALTER TABLE books
MODIFY id INT AUTO_INCREMENT;
#方式2:
ALTER TABLE books
MODIFY id INT PRIMARY KEY AUTO_INCREMENT;


#針對于非id字段的操作
ALTER TABLE books
MODIFY NAME VARCHAR(50) NOT NULL;

ALTER TABLE books
MODIFY AUTHORS VARCHAR(100) NOT NULL;

ALTER TABLE books
MODIFY price FLOAT NOT NULL;

ALTER TABLE books
MODIFY pubdate YEAR NOT NULL;

ALTER TABLE books
MODIFY num INT NOT NULL;


#練習3:

#1. 創(chuàng)建數(shù)據(jù)庫test04_company
CREATE DATABASE IF NOT EXISTS test04_company CHARACTER SET 'utf8';

USE test04_company;

#2. 按照下表給出的表結(jié)構(gòu)在test04_company數(shù)據(jù)庫中創(chuàng)建兩個數(shù)據(jù)表offices和employees

CREATE TABLE IF NOT EXISTS offices(
officeCode INT(10) PRIMARY KEY ,
city VARCHAR(50) NOT NULL,
address VARCHAR(50) ,
country VARCHAR(50) NOT NULL,
postalCode VARCHAR(15),
CONSTRAINT uk_off_poscode UNIQUE(postalCode)

);

DESC offices;

CREATE TABLE employees(
employeeNumber INT PRIMARY KEY AUTO_INCREMENT,
lastName VARCHAR(50) NOT NULL,
firstName VARCHAR(50) NOT NULL,
mobile VARCHAR(25) UNIQUE,
officeCode INT(10) NOT NULL,
jobTitle VARCHAR(50) NOT NULL,
birth DATETIME NOT NULL,
note VARCHAR(255),
sex VARCHAR(5),
CONSTRAINT fk_emp_offcode FOREIGN KEY (officeCode) REFERENCES offices(officeCode)

);

DESC employees;

#3. 將表employees的mobile字段修改到officeCode字段后面
ALTER TABLE employees
MODIFY mobile VARCHAR(25) AFTER officeCode;

#4. 將表employees的birth字段改名為employee_birth
ALTER TABLE employees
CHANGE birth employee_birth DATETIME;

#5. 修改sex字段,數(shù)據(jù)類型為CHAR(1),非空約束
ALTER TABLE employees
MODIFY sex CHAR(1) NOT NULL;


#6. 刪除字段note
ALTER TABLE employees
DROP COLUMN note;

#7. 增加字段名favoriate_activity,數(shù)據(jù)類型為VARCHAR(100)
ALTER TABLE employees
ADD favoriate_activity VARCHAR(100);

#8. 將表employees名稱修改為employees_info
RENAME TABLE employees
TO employees_info;

#錯誤:Table 'test04_company.employees' doesn't exist
DESC employees;

DESC employees_info;
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
有時間可以看看復習一下oracle-總結(jié)(轉(zhuǎn))
Linux系統(tǒng)下SQL Server數(shù)據(jù)庫操作
我的MYSQL學習心得(一)
數(shù)據(jù)庫部分(MySql)_4
MySQL_note
mysql中SQL語句修改2
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服