本章主要讲解外键约束以及其他约束的增加删除操作,通过本章将会对数据表列的操作更加熟练。
1.外键约束
目的:保持数据一致性,完整性;实现一对一或一对多关系。
约束保证数据的完整性和一致性
约束分为表级约束和列级约束(根据约束所针对的字段数目的多少决定)
列级约束:只针对表中的一个字段进行约束;
表级约束:针对表中的两个及以上字段进行约束。
约束类型包括:(功能划分)
NOT NULL(非空约束)
PRIMARY KEY(主键约束)
UNIQUE KEY(唯一约束)
DEFAULT(默认约束)
FOREIGN KEY(外键约束)
外键约束的要求:
- 父表和子表必须使用相同的存储引擎,而且禁止使用临时表
子表:具有外键列的表
父表:子表参照的表 - 数据表的存储引擎只能为InnoDB
- 外键列和参照列必须具有类似的数据类型。其中数字的长度或是否有符号位必须相同;而字符的长度则可以不同
外键列:加过FOREIGN 关键字的列
参照列:外键列所参照的列 - 外键列和参照列必须创建索引。 如果参照列不存在索引的话,MYSQL将自动创建索引
【外键约束】FOREIGN KEY(column) REFERENCES table(key)
【显示索引】SHOW INDEXES FROM [table]\G;
要创建外键约束必须满足以上四点要求。1)编辑数据表的默认存储引擎:
mysql配置文件(D:\MySQL\MySQL Server 5.5\my.ini 安装路径下):
default-storage-engine=INNODB;
(一般默认都为这个)2)创建数据类型相同的外键列和参照列
登录客户端,进入test数据库后,让我们来创建一个新的数据表:查看数据表是否采用了我们的默认引擎INNODB1
2
3
4
5mysql> CREATE TABLE provinces(
-> id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
-> pname varchar(20) NOT NULL
-> );
Query OK, 0 rows affected (0.05 sec)1
2
3
4
5
6
7
8
9
10
11mysql> SHOW CREATE TABLE provinces;
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| provinces | CREATE TABLE `provinces` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`pname` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)
可以看到ENGINE=InnoDB,说明设置成功。这样provinces数据表就创建好啦!
接下来创建另一个数据表
创建一个用户数据表,包括用户的id、姓名,还有存储用户所在的省份信息。以前添加省份信息的话,需要增加省份字段还要添加字符,现在是关系型数据库,并不需要这样做啦,只需要存储省份的id即可。
pid参考provinces 的id
1 | mysql> CREATE TABLE users( |
居然出现了错误,仔细观察就会发现,pid的数据类型为BIGINT和参考provinces中id的数据类型不一致,所以产生错误。
再来创建一次
1 | mysql> CREATE TABLE users( |
此时还是错误,说明大小不仅需要相同,是否有符号位,也必须相同。
最后一次
1 | mysql> CREATE TABLE users( |
user就是我们创建的子表,provinces就是父表。pid就是外键列, id就是参照列,当为数字的情况下时,要保证长度和是否有符号位相同,字符的情况下可以不同。
provinces的id并没有创建索引,但是系统有没有为我们自动创建呢,答案是肯定的,因为我们使用了主键约束,主键约束在创建的同时会自动创建索引。我们来证明一下是否存在索引:
1 | mysql> SHOW INDEXES FROM provinces; |
这样看的不直观,改一下命令:
1 | mysql> SHOW INDEXES FROM provinces\G; |
可以看到id字段已经有了索引 ( Column_name: id )
外键列的pid我们并没有创建主键,那么有没有创建索引呢?
1 | mysql> SHOW INDEXES FROM users\G; |
一共存在两个索引 Column_name: id (主键索引) Column_name: pid
主键在创建的时候会自动创建索引,外键在创建的时候也会自动创建索引。所以当参照列不是主键的时候不会自动创建索引,需要手动创建。
再看一下users数据表
1 | mysql> SHOW CREATE TABLE users; |
其中 KEY pid
(pid
),是系统自动给我们添加的。
索引和存储引擎会在后面详细介绍。
3)外键约束的参照操作
CASCADE:从父表删除或更新且自动删除或更新子表中匹配的行
SET NULL:从父表删除或更新行,并设置子表中的外键列为NULL。如果使用该选项,必须保证子表列没有指定NOT NULL
RESTRICT:拒绝对父表的删除或更新操作
NO ACTION:标准SQL的关键字,在MySQL中与RESTRICT相同
下面我们使用CASCADE做一个说明:
首先创建一个新的数据表和users一样,只是增加CASCADE
1 | mysql> CREATE TABLE users1( |
查看一下这个表
1 | mysql> SHOW CREATE TABLE users1; |
其中ON DELETE CASCADE就表示父表中更新或删除记录,子表也同时更新相应的行。
要对users1写入记录,就必须要对其父表先写入记录。原因很简单:如果不对父表写入记录,子表的pid将无从参照。
对provinces写入记录
1 | mysql> INSERT provinces(pname) VALUES('A'); |
查看一下
1 | mysql> SELECT * FROM provinces; |
对users1写入记录
1 | mysql> INSERT users1(username,pid) VALUES('hua',1); |
当我插入第三条记录时发生错误,因为父表中不存在这样的id。
外键约束所关联的父表字段值必须存在,子表中才能创建。
查看users1中的记录
1 | mysql> SELECT * FROM users1; |
当记录没写入成功时,编号仍然会自动递增,所以是1,2,4;
删除父表中id=3的记录
1 | mysql> DELETE FROM provinces WHERE id=3; |
注意:删除操作:DELETE FROM tbname WHERE 约束条件(id =3)
看一下父表的记录
1 | mysql> SELECT * FROM provinces; |
C已经被删除。
看一下子表的记录
1 | mysql> SELECT * FROM users1; |
pid为3的均被删除。
实际开发中不怎么使用物理外键,因为只有innodb引擎支持,通常使用逻辑外键。
物理外键指的是使用foreign key 作为外键关联另一张的字段的连接方法,而且限定了引擎为InnoDB,而逻辑外键,又叫做事实外键,在定义两张表时,是按照某种结构的方式去定义,不去使用foreign key 来定义。
4)表级约束与列级约束:
- 对一个数据列建立的约束,称为列级约束;
- 对多个数据列建立的约束,称为表级约束;
- 列级约束既可以在列定义时声明,也可以在列定义后声明;
- 表级约束只能在列定义后声明;
- 并不是所有约束都存在表级约束。如NOT NULL 和DEFAULT约束是不存在表级约束的;
实际开发过程中,很少使用表级约束。5)修改数据表
添加列
ALTER TABLE table_name ADD [COLUMN] column_name column_definition [FIRST | AFTER column_name]
FIRST :添加到列的第一个位置
AFTER column_name:在指定列的后面
默认添加到最后。
现在我们来实战演练一下,列的添加。
先看一个users1的列信息
1 | mysql> SHOW COLUMNS FROM users1; |
接下来添加一列
1 | mysql> ALTER TABLE users1 ADD age TINYINT UNSIGNED NOT NULL DEFAULT 10; |
查看一下数据表结构
1 | mysql> SHOW COLUMNS FROM users1; |
可以看出默认插入到最后一列。
再使用FIRST插入一列
1 | mysql> ALTER TABLE users1 ADD password VARCHAR(20) NOT NULL FIRST; |
再次查看数据表结构就会发现,password在第一例的位置。这里不再演示。
使用AFTER插入一列
1 | mysql> ALTER TABLE users1 ADD habital VARCHAR(20) NOT NULL AFTER username; |
habital被添加在username的后面。
添加多列
ALTER TABLE tbl_name ADD [COLUMN] (col_name column_definiton,…)
和添加一列基本类似,不再操作。需要注意的是,添加多列时,不能指定位置,只能在列尾添加。
删除列
ALTER TABLE tbl_name DROP [COLUMN] col_name
如:ALTER TABLE user1 DROP truename;删除表user1的truename单列
如:ALTER TABLE user1 DROP password,DROP age;删除多列,用逗号分隔开
删除password列
1 | mysql> ALTER TABLE users1 DROP password; |
查看一下:
1 | mysql> SHOW COLUMNS FROM users1; |
如果我想删除多列呢?
删除多列,通过“,”隔开即可
1 | mysql> ALTER TABLE users1 DROP age,DROP habital; |
再查看一下吧
1 | mysql> SHOW COLUMNS FROM users1; |
6)添加约束
当约束不够时,如何增加约束?或者如何删除约束?
为此,我们先创建一个新的数据表:
1 | mysql> CREATE TABLE users2( |
添加主键约束
ALTER TABLE tbl_name ADD [CONSTRAINT [symbol]] PRIMARYKEY [index_type] (index_col_name,…)
CONSTRAINT 可以添加也可以不添加,如果添加可以起个名字。
1 | mysql> ALTER TABLE users2 ADD CONSTRAINT PK_users2_id PRIMARY KEY (id); |
再来看一下数据表的结构:
1 | mysql> SHOW COLUMNS FROM users2; |
可以看到id已经变为主键约束。
添加唯一约束
ALTER TABLE tbl_name ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,…)
与主键约束不同的是唯一约束可以有多个。
下面我们给pid添加一个唯一约束:
1 | mysql> ALTER TABLE users2 ADD UNIQUE (pid); |
检查一下数据表结构:
1 | mysql> SHOW COLUMNS FROM users2; |
pid已经被设置为唯一约束。
添加外键约束
ALTER TABLE tb1_name ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] [index_type] (index_col_name,…) reference_definition;
首先看一下要设置的父表的结构(还是我们之前的provinces):
1 | mysql> SHOW COLUMNS FROM provinces; |
添加一个和id类型一样的列:
1 | mysql> ALTER TABLE users2 ADD cid SMALLINT UNSIGNED; |
接下来设置username的外键约束:
1 | mysql> ALTER TABLE users2 ADD FOREIGN KEY (cid) REFERENCES provinces (id); |
查看一下:
1 | mysql> SHOW CREATE TABLE users2; |
cid已经被设置为外键约束。
添加/删除默认约束
ALTER TABLE tbl_name ALTER[COLUMN] col_name{SET DEFAULT literal|DROP DEFAULT}
1 | mysql> ALTER TABLE users2 ALTER COLUMN username SET DEFAULT 'pp'; |
查看列信息:
1 | mysql> SHOW COLUMNS FROM users2; |
username的默认值被设置为‘pp’。
下面删除默认约束:
1 | mysql> ALTER TABLE users2 ALTER COLUMN username DROP DEFAULT; |
看下是否被删除:
1 | mysql> SHOW COLUMNS FROM users2; |
大功告成!
7)删除约束
删除主键约束
ALTER TABLE tbl_name DROP PRIMARY KEY
不需要指定名称,因为一张表只有一个主键
1 | mysql> ALTER TABLE users2 DROP PRIMARY KEY; |
查看一下:
1 | mysql> SHOW COLUMNS FROM users2; |
删除唯一约束
ALTER TABLE tbl_name DROP {INDEX|KEY} index_name
需要指定名称,因为一张表可以有多个唯一约束
我们接下来要删除的是唯一约束,所以首先我们应该查看约束的名字:
1 | mysql> SHOW INDEXES FROM users2\G; |
删除pid的约束:
1 | mysql> ALTER TABLE users2 DROP KEY pid; |
现在只剩下一个约束:
1 | mysql> SHOW INDEXES FROM users2\G; |
删除外键约束
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol
要想删除外键约束,必须知道外键约束的名字;
1 | mysql> SHOW CREATE TABLE users2; |
可以得到外键的名字为 users2_ibfk_1
下面进行删除:
1 | mysql> ALTER TABLE users2 DROP FOREIGN KEY users2_ibfk_1; |
查看:
1 | mysql> SHOW CREATE TABLE users2; |
可以看到cid还是存在索引的,如果不想要还可以进一步进行删除:
1 | mysql> ALTER TABLE users2 DROP KEY cid; |
再来查看一下:
1 | mysql> SHOW CREATE TABLE users2; |
cid的索引已经删除。
8)修改列定义和更名数据表
修改列定义
(列名字不存在问题,列的类型或者位置可能存在问题)
ALTER TABLE tbl_name MODIFY [COLUMN] col_name colunm_definition [FIRST | AFTER col_name]
修改列名称
(既可以修改列定义,也可以修改列名称)
ALTER TABLE tbl_name CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name]
数据表更名
(列名称和数据表名称尽量不要改动,因为实际使用中可能会有关联,导致存储过程出现问题)
方法1
ALTER TABLE tbl_name RENAME [TO|AS] new_tbl_name
方法2(可以修改多张表的名称)
RENAME TABLE tbl_name TO new_tbl_name [,tbl_name2 TO new_tbl_name2]…
小结:
约束按照功能来划分:
not null(非空约束)
primary key(主键约束)
unique key(唯一约束)
default(默认约束)
foreign key(外键约束)
按照数据列的数目划分:
表级约束
列级约束
修改数据表的操作:
针对字段的操作:添加/删除字段。修改列定义,修改列名称
针对约束的操作:添加/删除约束
针对数据表的操作:数据表更名(两种方式)