數(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倍。約束是表級的強制規(guī)定。
可以在創(chuàng)建表時規(guī)定約束(通過 CREATE TABLE 語句),或者在表創(chuàng)建之后通過 ALTER TABLE 語句規(guī)定約束。
位置 支持的約束類型 是否可以起約束名
列級約束: 列的后面 語法都支持,但外鍵沒有效果 不可以
表級約束: 所有列的下面 默認和非空不支持,其他支持 可以(主鍵沒有效果)
注意: MySQL不支持check約束,但可以使用check約束,而沒有任何效果
#information_schema數(shù)據(jù)庫名(系統(tǒng)庫)
#table_constraints表名稱(專門存儲各個表的約束)
SELECT * FROM information_schema.table_constraints
WHERE table_name = '表名稱';
限定某個字段/某列的值不允許為空
NOT NULL
(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;
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;
用來限制某個字段/某列的值不能重復。
UNIQUE
MySQL會給唯一約束的列上默認創(chuàng)建一個唯一索引。
(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);
復合唯一約束的字段列表, 在添加記錄的時候, 字段列表不能同時相同;
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的復合唯一
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名'; #查看都有哪些約束
ALTER TABLE USER
DROP INDEX uk_name_pwd;
注意:可以通過
show index from 表名稱;
查看表的索引
用來唯一標識表中的一行記錄。
primary key
(唯一且非空)
一個表最多只能有一個主鍵約束,建立主鍵約束可以在列級別創(chuàng)建,也可以在表級別上創(chuàng)建。
主鍵約束對應著表中的一列或者多列(復合主鍵)
如果是多列組合的復合主鍵約束,那么這些列都不允許為空值,并且組合的值不允許重復。
MySQL的主鍵名總是PRIMARY
,就算自己命名了主鍵約束名也沒用。
當創(chuàng)建主鍵約束時,系統(tǒng)默認會在所在的列或列組合上建立對應的主鍵索引(能夠根據(jù)主鍵查詢的,就根據(jù)主鍵查詢,效率更高)。如果刪除主鍵約束了,主鍵約束對應的索引就自動刪除了。
需要注意的一點是,不要修改主鍵字段的值。因為主鍵是數(shù)據(jù)記錄的唯一標識,如果修改了主鍵的值,就有可能會破壞數(shù)據(jù)的完整性。
(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); # 復合主鍵
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)
);
alter table 表名稱 drop primary key;
舉例:
ALTER TABLE student DROP PRIMARY KEY;
ALTER TABLE emp5 DROP PRIMARY KEY;
說明:刪除主鍵約束,不需要指定主鍵名,因為一個表只有一個主鍵,刪除主鍵約束后,非空還存在。
某個字段的值自增
開發(fā)中, 如果主鍵設置了自增, 一般我們寫sql的時候, 就不用在寫主鍵列了
auto_increment
(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ù)類型
(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)
#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)
在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)存值。
限定某個表的某個字段的引用完整性。
比如:員工表的員工所在部門的選擇,必須在部門表能找到對應的部分。
下圖: 員工表就是從表; 部門表是主表
FOREIGN KEY
主表(父表):被引用的表,被參考的表
從表(子表):引用別人的表,參考別人的表
例如:員工表的員工所在部門這個字段的值要參考部門表:部門表是主表,員工表是從表。
例如:學生表、課程表、選課表:選課表的學生和課程要分別參考學生表和課程表,學生表和課程表是主表,選課表是從表。
(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)刪除外鍵約束后,必須手動
刪除對應的索引
(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);
(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é):約束關系是針對雙方的
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)
流程如下:
(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;
問題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ù)的一致性。
【強制
】不得使用外鍵與級聯(lián),一切外鍵概念必須在應用層解決。
說明:(概念解釋)學生表中的 student_id 是主鍵,那么成績表中的 student_id 則為外鍵。如果更新學生表中的 student_id,同時觸發(fā)成績表中的 student_id 更新,即為級聯(lián)更新。外鍵與級聯(lián)更新適用于單機低并發(fā)
,不適合分布式
、高并發(fā)集群
;級聯(lián)更新是強阻塞,存在數(shù)據(jù)庫更新風暴
的風險;外鍵影響數(shù)據(jù)庫的插入速度
。
檢查某個字段的值是否符號xx要求,一般指的是值的范圍
CHECK
在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)
給某個字段/某列指定默認值,一旦設置默認值,在插入數(shù)據(jù)時,如果此字段沒有顯式賦值,則賦值為默認值。
DEFAULT
(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)
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)
面試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開始的嗎?
面試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;
聯(lián)系客服