PRIMARY KEY
MySQL 主键约束是一个列或者列的组合,其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键,通过它可以强制表的实体完整性。
主键约束即在表中定义一个主键来唯一确定表中每一行数据的标识符。主键可以是表中的某一列或者多列的组合,其中由多列组合的主键称为复合主键。
主键应该遵守下面的规则:
在定义列的同时指定主键,语法规则如下:
<字段名> <数据类型> PRIMARY KEY [默认值],
这种方法不允许将多个列同时声明为主键,多个列同时被声明为主键的话会报错。
例子:
mysql> CREATE TABLE `stu` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(20), `score` FLOAT(4,1));
Query OK, 0 rows affected (0.11 sec)
mysql> DESC `stu`;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| score | float(4,1) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
在定义完所有列之后,指定主键的语法格式为:
<列定义1>, ..., <列定义n>, PRIMARY KEY (字段名)
例如:
mysql> CREATE TABLE `stu` (`id` INT(11), `name` VARCHAR(20), PRIMARY KEY (`id`));
Query OK, 0 rows affected (0.05 sec)
mysql> DESC `stu`;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
设置复合主键的话只能在所有列定义的最后统一声明主键约束,在列定义中声明主键的话只能设置单个主键,不能设置复合主键。
语法,定义完所有列之后:
<列定义1>, ..., <列定义n>, PRIMARY KEY (字段1,字段2,…,字段n)
例如:
如果没有id
的话,可以将员工姓名与部门id
作为复合主键。
mysql> CREATE TABLE `staff` (`name` VARCHAR(20), `deptId` INT(11), `salary` DEC(10,2), PRIMARY KEY (`name`, `deptId`));
Query OK, 0 rows affected (0.06 sec)
mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name | varchar(20) | NO | PRI | NULL | |
| deptId | int(11) | NO | PRI | NULL | |
| salary | decimal(10,2) | YES | | NULL | |
+--------+---------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
ALTER TABLE <数据表名> ADD PRIMARY KEY(<列名>);
前提是表中本来没有设置主键约束,否则会报错,提示已经有主键约束。
也可以新增字段的同时将字段设为主键:
ALTER TABLE <数据表名> ADD <字段名> <字段类型> PRIMARY KEY;
例如,表staff
中本来没有id
字段,也没有主键约束:
mysql> ALTER TABLE `staff` ADD `id` INT(11) PRIMARY KEY;
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| deptId | int(11) | NO | | NULL | |
| salary | decimal(10,2) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | |
+--------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
修改表的主键约束需要先删除主键约束,然后再添加主键约束。
ALTER TABLE <表名> DROP PRIMARY KEY;
ALTER TABLE <表名> ADD PRIMARY KEY (主键字段);
例如:
mysql> ALTER TABLE `staff` DROP PRIMARY KEY;
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE `staff` ADD PRIMARY KEY (`id`);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| deptId | int(11) | NO | | NULL | |
| salary | decimal(10,2) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | |
+--------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
FOREIGN KEY
外键约束(FOREIGN KEY
)用来在两个表的数据之间建立链接,它可以是一列或者多列。一个表可以有一个或多个外键。
父表和子表
外键的主要作用是保持数据的一致性、完整性。例如,部门表 tb_dept
的主键是 id
,在员工表 tb_emp
中有一个键 deptId
与这个 id
关联。
一个简单的判断方法:当两个表建立一对多关系的时候,"一"的那一端是父表,"多"的那一端是子表。
定义一个外键时,需要遵守下列规则:
参照完整性
参照完整性是相关联的两个表之间的约束,具体的说,就是从表中每条记录外键的值必须是主表中存在的。
如果实施了参照完整性,那么当主表中没有相关记录时,就不能将记录添加到相关表中。也不能在相关表中存在匹配的记录时删除主表中的记录,更不能在相关表中有相关记录时,更改主表中的主键值。也就是说,实施了参照完整性后,对表中主键字段进行操作时系统会自动地检查主键字段,看看该字段是否被添加、修改、删除了。如果对主键的修改违背了参照完整性的要求,那么系统就会自动强制执行参照完整性。
在定义完所有的列以后:
<列定义1>, ..., <列定义n>, [CONSTRAINT <外键名>] FOREIGN KEY (字段名 [,字段名2,…]) REFERENCES <主表名> (主键列1 [,主键列2,…])
如果不设置外键名的话会自动生成外键名,名字类似于:从表名_ibfk_1
。
例子,员工和部门表:
# 首先创建主表,即部门表
mysql> CREATE TABLE `dept` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(40) NOT NULL, `leader` VARCHAR(30));
Query OK, 0 rows affected (0.04 sec)
# 然后创建从表,即员工表
mysql> CREATE TABLE `staff` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(40) NOT NULL, `salary` DEC(10, 2), `dept_id` INT(11), FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`));
Query OK, 0 rows affected (0.03 sec)
mysql> DESC `staff`;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(40) | NO | | NULL | |
| salary | decimal(10,2) | YES | | NULL | |
| dept_id | int(11) | YES | MUL | NULL | |
+---------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> DESC `dept`;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(40) | NO | | NULL | |
| leader | varchar(30) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
ALTER TABLE <数据表名> ADD CONSTRAINT <外键名> FOREIGN KEY(<列名>) REFERENCES <主表名> (<列名>);
例子:
# 首先创建一个没有设置外键约束的表
mysql> CREATE TABLE `staff_2` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(20) NOT NULL, `dept_id` INT(11) NOT NULL);
Query OK, 0 rows affected (0.03 sec)
# 添加名为'staff_2_fk_test',约束类型为外键约束的约束
mysql> ALTER TABLE `staff_2` ADD CONSTRAINT `staff_2_fk_test` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`);
Query OK, 0 rows affected (0.08 sec)
Records: 0 Duplicates: 0 Warnings: 0
# 查看名为'staff_2_fk_test'的约束详情
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_2_fk_test'\G
*************************** 1. row ***************************
CONSTRAINT_CATALOG: def
CONSTRAINT_SCHEMA: test
CONSTRAINT_NAME: staff_2_fk_test
TABLE_CATALOG: def
TABLE_SCHEMA: test
TABLE_NAME: staff_2
COLUMN_NAME: dept_id
ORDINAL_POSITION: 1
POSITION_IN_UNIQUE_CONSTRAINT: 1
REFERENCED_TABLE_SCHEMA: test
REFERENCED_TABLE_NAME: dept
REFERENCED_COLUMN_NAME: id
1 row in set (0.08 sec)
ALTER TABLE <表名> DROP FOREIGN KEY <外键约束名>;
不知道外键名的话可以先通过查看约束的方法找到外键名。
例子:
mysql> ALTER TABLE `staff_2` DROP FOREIGN KEY staff_2_fk_test;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
UNIQUE
MySQL唯一约束(Unique Key
)要求该列唯一,允许为空,但只能出现一个空值。唯一约束可以确保一列或者几列不出现重复值。
提示:
PRIMARY KEY
也是不允许重复的,UNIQUE
和PRIMARY KEY
的区别:一个表可以有多个字段声明为UNIQUE
,但只能有一个PRIMARY KEY
声明;声明为PRIMAY KEY
的列不允许有空值,但是声明为UNIQUE
的字段允许空值的存在。
在创建表时定义完某个列之后直接使用 UNIQUE
关键字指定唯一约束,语法规则如下:
<字段名> <数据类型> UNIQUE
ALTER TABLE <数据表名> ADD CONSTRAINT <唯一约束名> UNIQUE(<列名>);
ALTER TABLE <表名> DROP INDEX <唯一约束名>;
CHECK
检查约束用于对表中的数据进行一些限制(比如年龄大于0等),防止插入一些非法的值,在更新表的时候会对数据进行检查。
可以在列定义的时候对列设置约束条件(基于列的CHECK
约束),也可以在所有列声明完以后同时对多个列设置约束(基于表的CHECK
约束)。
CHECK
但是要注意,在MySQL中,设置CHECK
约束是不会起作用的,MySQL语句中接收CHECK
子句,但是会将其忽略,因此设置CHECK
约束后任然可以插入不符合CHECK
约束的数据。可能是为了保证数据库之间的数据兼容性什么的。
解决方案:
ENUM
枚举类型来进行限制。TRIGGER
触发器来实现。CHECK(<检查约束>)
例如:
# 设置列约束
mysql> CREATE TABLE `staff` (`id` INT(11) CHECK(`id`>0), `name` VARCHAR(20));
Query OK, 0 rows affected (0.03 sec)
# 设置表约束
mysql> CREATE TABLE `staff` (`id` INT(11), `name` VARCHAR(20), CHECK(`id`>0 AND CHAR_LENGTH(`name`)>3));
Query OK, 0 rows affected (0.05 sec)
ALTER TABLE tb_emp7 ADD CONSTRAINT <检查约束名> CHECK(<检查约束>)
MySQL将CHECK
子句忽略掉了,因此没有保存CHECK
信息,也无需删除。
ALTER TABLE <数据表名> DROP CONSTRAINT <检查约束名>;
ALTER TABLE <数据表名> DROP CHECK <检查约束名>;
TRIGGER
触发器示例可以针对BEFORE INSERT
和BEFORE UPDATE
设置触发器,使在插入数据或者更新数据之前检查数据有效性。
下面是设置BEFORE INSERT
触发器示例:
mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer
-> FOR EACH ROW
-> BEGIN
-> IF NEW.SD<0 THEN
-> SET NEW.SD=0;
-> END IF;
-> END
-> //
mysql> delimiter ;
DEFAULT
<字段名> <数据类型> DEFAULT <默认值>;
CHANGE
| MODIFY
ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> DEFAULT <默认值>;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> DEFAULT <默认值>;
DEFAULT NULL
把默认值修改为NULL
即可删除默认值约束。
ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> DEFAULT NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> DEFAULT NULL;
NOT NULL
和DEFAULT NULL
类似。
<字段名> <数据类型> NOT NULL;
CHANGE
| MODIFY
ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> NOT NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> NOT NULL;
NULL
把默认值修改为NULL
即可删除默认值约束。
ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> NULL;
如果表中已经有该字段值为NULL
的数据,则无法修改成功,会报错。
SHOW CREATE TABLE
查看约束SHOW CREATE TABLE <数据表名>;
SHOW CREATE TABLE <数据表名> \G
information_schema
数据库中查询约束约束会被保存在information_schema
数据库中,可以用SHOW TABLES IN information_schema;
列出该数据库中所有的表格。
约束信息在information_schema.KEY_COLUMN_USAGE
、information_schema.REFERENTIAL_CONSTRAINTS
这两个表格中,information_schema.KEY_COLUMN_USAGE
包含所有约束的信息。
查询的时候可以通过WHERE
根据CONSTRAINT_NAME
(约束名)、CONSTRAINT_SCHEMA
(约束所在的数据库名)、TABLE_SCHEMA
(从表所在数据库名)、TABLE_NAME
(从表名)、COLUMN_NAME
(从表外键字段名)、REFERENCED_TABLE_SCHEMA
(主表所在数据库名)、REFERENCED_TABLE_NAME
(主表名)、REFERENCED_COLUMN_NAME
(主表字段名)等字段进行筛选。
# 根据主表名查看约束
SELECT * FROM information_schema.key_column_usage WHERE `REFERENCED_TABLE_NAME`='主表名';
# 根据约束名查看约束
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='约束名';
# 查看主键约束
# 查看所有的主键约束(很多,建议再加上数据库名或者表名等)
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='PRIMARY';
# 查看某个数据库中所有的主键约束
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='PRIMARY' AND `CONSTRAINT_SCHEMA`='数据库名';
SELECT constraint_name FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE `constraint_schema` = 'db_name' AND `table_name` = 'table_name';
例子:
# 查看约束名为'staff_ibfk_1'的约束
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_ibfk_1';
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | ORDINAL_POSITION | POSITION_IN_UNIQUE_CONSTRAINT | REFERENCED_TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
| def | test | staff_ibfk_1 | def | test | staff | dept_id |
1 | 1 | test | dept | id
|
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
1 row in set (0.08 sec)
# 以垂直的方式(即清单的方式)呈现
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_ibfk_1'\G
*************************** 1. row ***************************
CONSTRAINT_CATALOG: def
CONSTRAINT_SCHEMA: test
CONSTRAINT_NAME: staff_ibfk_1
TABLE_CATALOG: def
TABLE_SCHEMA: test
TABLE_NAME: staff
COLUMN_NAME: dept_id
ORDINAL_POSITION: 1
POSITION_IN_UNIQUE_CONSTRAINT: 1
REFERENCED_TABLE_SCHEMA: test
REFERENCED_TABLE_NAME: dept
REFERENCED_COLUMN_NAME: id
1 row in set (0.10 sec)
MySQL教程:MySQL数据库学习宝典(从入门到精通)——C语言中文网
MySQL 教程 | 菜鸟教程
参照完整性_百度百科