原文: http://blog.gqylpy.com/gqy/249
"
目录
约束条件与数据类型的宽度一样,都是可选参数
作用:用于保证数据的完整性和一致性
主要分为:
- primary key (pk) # 标识该字段为该表的主键,能够唯一的标识记录
- foreign key (pk) # 标识该字段为该表的外键
- not null # 标识该字段不能为空
- unique key (uk) # 标识该字段的值是唯一的
- auto_increment # 标识该字段的值自动增长(整数类型,而且为主键)
- default # 为该字段设置默认值
- unsigned # 无符号
- zerofill # 使用0填充
说明:
- 是否允许为空,默认为null,设置not null,使字段不允许为空,必须赋值.
- 字段是否有默认值,缺省的默认值是null,如果插入记录时不给字段赋值,则此字段使用默认值null.
(设置枚举的默认值,且不为空:sex enum('boy', 'girl') not null default 'boy')
(设置年龄必须为正值(无符号)且不为空,默认为20:age int unsigned not null default 20)
not null
设置not null,插入值时不能为空.
# 创建测试表mysql> create table test(id int not null);Query OK, 0 rows affected (0.08 sec) # 此时查看表结构,Null的标识为NO,即不允许为空 mysql> desc test;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id | int(11) | NO | | NULL | |+-------+---------+------+-----+---------+-------+1 row in set (0.00 sec) # 插入一个空字符串是可以的(本人是在Mac系统上实测,这一步骤可能与Windows或Linux有差异)mysql> insert into test values();Query OK, 1 row affected, 1 warning (0.03 sec) # 插入null时,直接报错mysql> insert into test values(null);ERROR 1048 (23000): Column 'id' cannot be null # 此时查询记录# 可见:int类型设置not null后,插入空字符串会替换成0mysql> select * from test;+----+| id |+----+| 0 |+----+1 row in set (0.00 sec)
default
设置一个字段有默认值后,则无论这个字段是null还是not null,都可以插入空,插入空默认填入default指定的默认值.
# 第一种情况:defaultmysql> create table test(id int default 1);Query OK, 0 rows affected (0.07 sec) mysql> desc test;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id | int(11) | YES | | 1 | |+-------+---------+------+-----+---------+-------+1 row in set (0.00 sec) mysql> insert into test values();Query OK, 1 row affected (0.04 sec) mysql> select * from test;+------+| id |+------+| 1 |+------+1 row in set (0.00 sec) # 第二种情况:not null + defaultmysql> create table test(id int not null default 2);Query OK, 0 rows affected (0.05 sec) mysql> desc test;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id | int(11) | NO | | 2 | |+-------+---------+------+-----+---------+-------+1 row in set (0.00 sec) mysql> insert into test values();Query OK, 1 row affected (0.04 sec) mysql> select * from test;+----+| id |+----+| 2 |+----+1 row in set (0.00 sec)
unique
中文翻译:不同的。在MySQL中称为单列唯一
单列唯一
# 创建unique方式1:# 指定name唯一mysql> create table test( -> id int, -> name char(3) unique -> );Query OK, 0 rows affected (0.17 sec) # 插入相同的name,直接报错mysql> insert into test values(1, 'zyk'), (2, 'zyk');ERROR 1062 (23000): Duplicate entry 'zyk' for key 'name' # 此时正常mysql> insert into test values(1, 'zyk'), (2, 'xhh');Query OK, 2 rows affected (0.01 sec)Records: 2 Duplicates: 0 Warnings: 0 # 创建unique方式2:mysql> create table test( -> id int, -> name char(3), -> unique(id), -> unique(name) -> );Query OK, 0 rows affected (0.09 sec) # 可见:Key标识为UNImysql> desc test;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id | int(11) | YES | UNI | NULL | || name | char(3) | YES | UNI | NULL | |+-------+---------+------+-----+---------+-------+2 rows in set (0.00 sec)
联合唯一
即指定表中两条或以上的记录,只有当这些被指定的记录都相同时才符合联合唯一,否则不会被限制.
mysql> create table test( -> ip char(15), -> port int, -> unique(ip, port) # 联合唯一 -> );Query OK, 0 rows affected (0.08 sec) # 此时查看表结构,Key的标识为MULmysql> desc test;+-------+----------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+----------+------+-----+---------+-------+| ip | char(15) | YES | MUL | NULL | || port | int(11) | YES | | NULL | |+-------+----------+------+-----+---------+-------+2 rows in set (0.00 sec) # 插入两条不完全相同的数据mysql> insert into test values -> ('192.168.1.1', 3306), -> ('192.168.1.2', 3306);Query OK, 2 rows affected (0.03 sec) # 成功插入Records: 2 Duplicates: 0 Warnings: 0 # 再插入一条存在的数据,被阻止mysql> insert into test values('192.168.1.1', 3306);ERROR 1062 (23000): Duplicate entry '192.168.1.1 -3306' for key 'ip'
primary key
一张表中可以:单列做主键,多列做主键(复合主键)
约束:字段的值不为空且值唯一,等价于not null unique
MySQL的存储引擎默认是InnoDB,对于InnoDB存储引擎来说,一张表必须有一个主键.
单列主键
mysql> create table test( -> id int primary key, # 单列主键 -> name char(3) -> );Query OK, 0 rows affected (0.05 sec) # 此时查看表结构,Key的标识为PRImysql> desc test;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id | int(11) | NO | PRI | NULL | || name | char(3) | YES | | NULL | |+-------+---------+------+-----+---------+-------+2 rows in set (0.00 sec) # 插入两条id不同的数据mysql> insert into test values -> (1, 'zyk'), -> (2, 'xhh');Query OK, 2 rows affected (0.00 sec)Records: 2 Duplicates: 0 Warnings: 0 # id已存在,阻止插入mysql> insert into test value(2, 'jein');ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
复合主键
复合主键与联合唯一同理:
指定表中两条或以上的记录,只有当这些被指定的记录都相同时才符合复合主键的限制,否则不会被限制.
mysql> create table test( -> ip char(15), -> port int, -> primary key(ip, port) # 复合主键 -> );Query OK, 0 rows affected (0.06 sec) mysql> insert into test values -> ('192.168.1.1', 3306), -> ('192.168.1.2', 3306);Query OK, 2 rows affected (0.00 sec)Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into test values('192.168.1.1', 3306);ERROR 1062 (23000): Duplicate entry '192.168.1.1 -3306' for key 'PRIMARY' mysql> desc test;+-------+----------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+----------+------+-----+---------+-------+| ip | char(15) | NO | PRI | NULL | || port | int(11) | NO | PRI | NULL | |+-------+----------+------+-----+---------+-------+2 rows in set (0.01 sec)
auto_increment
被约束的字段自动增长,且必须同时被key约束.
不指定id,则自动增长:
mysql> create table test( -> id int primary key auto_increment, # 约束字段自动增长 -> name varchar(20), -> sex enum('boy', 'girl') default 'boy' -> );Query OK, 0 rows affected (0.05 sec) # 表结构显示Extra的标识为auto_increment,即自动增长mysql> desc test;+-------+--------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+--------------------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || name | varchar(20) | YES | | NULL | || sex | enum('boy','girl') | YES | | boy | |+-------+--------------------+------+-----+---------+----------------+3 rows in set (0.00 sec) # 插入两条记录mysql> insert into test(name) values ('zyk'), ('xhh');Query OK, 2 rows affected (0.00 sec)Records: 2 Duplicates: 0 Warnings: 0 # 可见,id确为自动增长mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 1 | zyk | boy || 2 | xhh | boy |+----+------+------+2 rows in set (0.00 sec)
指定id:
# 指定id插入两条数据mysql> insert into test values -> (4, 'join', 'girl'), -> (7, 'lay', 'girl');Query OK, 2 rows affected (0.01 sec)Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 1 | zyk | boy || 2 | xhh | boy || 4 | join | girl || 7 | lay | girl |+----+------+------+4 rows in set (0.00 sec) # 再次插入一条不指定id的记录,会随着值最大的id+1mysql> insert into test(name) values ('great white');Query OK, 1 row affected (0.00 sec) mysql> select * from test;+----+-------------+------+| id | name | sex |+----+-------------+------+| 1 | zyk | boy || 2 | xhh | boy || 4 | join | girl || 7 | lay | girl || 8 | great white | boy |+----+-------------+------+5 rows in set (0.00 sec) # mysql> insert into test(id, name) values (3, 'aaa');Query OK, 1 row affected (0.04 sec) mysql> select * from test;+----+-------------+------+| id | name | sex |+----+-------------+------+| 1 | zyk | boy || 2 | xhh | boy || 3 | aaa | boy || 4 | join | girl || 7 | lay | girl || 8 | great white | boy |+----+-------------+------+6 rows in set (0.00 sec)
对于自增的字段,在用delete删除后,再插入值,改字段仍按照删除前的位置继续增长.
应使用truncate清空表,trunacte是直接清空表,再删除数据量庞大的表时非常有用.
# delete删除表记录mysql> delete from test;Query OK, 8 rows affected (0.00 sec) mysql> insert into test(name) values('zyk');Query OK, 1 row affected (0.04 sec) # 可见:delete删除表记录后,再插入值,仍然是按照删除前的位置继续增长mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 9 | zyk | boy |+----+------+------+1 row in set (0.00 sec) # truncate清空表mysql> truncate test;Query OK, 0 rows affected (0.00 sec) mysql> insert into test(name) values('zyk');Query OK, 1 row affected (0.00 sec) # 此时id重新开始自增mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 1 | zyk | boy |+----+------+------+1 row in set (0.00 sec)
清空表分区 delete 与 truncate 的区别:
- delete from tb # 有自增id时,删除后新增的数据的id仍然是按照未删除之前最大的id+1计算的
- truncate table tb # 直接清空表,数据量大时非常适用,删除速度比delete快,且id直接从0开始
步长与偏移量
auto_increment_increment:步长,默认为1
auto_increment_offset:起始的偏移量,默认为1
注意:如果偏移量大于步长,则偏移量的会被重设为1
# 查看步长与偏移量mysql> show variables like 'auto_i%';+--------------------------+-------+| Variable_name | Value |+--------------------------+-------+| auto_increment_increment | 1 | # 步长| auto_increment_offset | 1 | # 偏移量+--------------------------+-------+2 rows in set (0.00 sec) # session为会话设置,只在本次链接中有效mysql> set session auto_increment_increment = 5;Query OK, 0 rows affected (0.00 sec) # global全局(设置后需重新连接,才会生效)mysql> set global auto_increment_increment = 5;Query OK, 0 rows affected (0.00 sec) mysql> set global auto_increment_offset = 3;Query OK, 0 rows affected (0.00 sec) # 重新连接后查看mysql> show variables like 'auto_i%';+--------------------------+-------+| Variable_name | Value |+--------------------------+-------+| auto_increment_increment | 5 || auto_increment_offset | 3 |+--------------------------+-------+2 rows in set (0.00 sec) # 先清空表mysql> truncate table test;Query OK, 0 rows affected (0.04 sec) # 插入一条记录,可见:id是从3开始计算的mysql> insert into test(name) values ('zyk');Query OK, 1 row affected (0.04 sec) mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 3 | zyk | boy |+----+------+------+1 row in set (0.01 sec) # 再插入几条数据,可见:id每次自增5mysql> insert into test(name) values ('zyk1'), ('zyk2'), ('zyk3');Query OK, 3 rows affected (0.00 sec)Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from test;+----+------+------+| id | name | sex |+----+------+------+| 3 | zyk | boy || 8 | zyk1 | boy || 13 | zyk2 | boy || 18 | zyk3 | boy |+----+------+------+4 rows in set (0.00 sec)
foreign key
一 快速理解foreign key
之前创建表的时候都是在一张表中添加记录,比如如下表:

公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费。
这个时候,
解决方法:
我们完全可以定义一个部门表
然后让员工信息表关联该表,如何关联,即foreign key
我们可以将上表改为如下结构:

此时有两张表:
一张是employee表,简称emp表(关联表,也从从表)
一张是department表,简称dep表(被关联表,也叫主表)
注意:被关联表称为主表,关联表(也就是设置外键的表)称为从表.
# 先建立主表mysql> create table dep( -> id int primary key, -> name varchar(20) not null, -> descripe varchar(20) not null -> );Query OK, 0 rows affected (0.07 sec) # 再建立从表mysql> create table emp( -> id int primary key, -> name varchar(20) not null, -> age int not null, -> dep_id int, # 与主表建立关联, fk_dep为自定义的外键名,不可重复: -> constraint fk_dep foreign key(dep_id) references dep(id) -> );Query OK, 0 rows affected (0.05 sec) mysql> insert into dep values -> (1, "技术部", "各个大牛部们"), -> (2, "销售部", "一本正经胡说八道部门"), -> (3, "财务部", "花钱太多部门");Query OK, 3 rows affected (0.00 sec)Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into emp values -> (1, 'zyk', 19, 1), -> (2, 'xhh', 18, 2), -> (3, 'jein', 18, 3), -> (4, 'egon', 18, 2), -> (5, 'lisi', 18, 3);Query OK, 5 rows affected (0.04 sec)Records: 5 Duplicates: 0 Warnings: 0 # 如果从表中有与主表中关联的行,则不允许删除主表中的被关联的行mysql> delete from dep where id=1;ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`db`.`emp`, CONSTRAINT `fk_dep` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`)) # 删除从表中与主表中关联的的行(dep_id=1)mysql> delete from emp where dep_id = 1;Query OK, 1 row affected (0.03 sec) # 此时可删除主表中的数据mysql> delete from dep where id = 1;Query OK, 1 row affected (0.01 sec) mysql> select * from dep;+----+-----------+--------------------------------+| id | name | descripe |+----+-----------+--------------------------------+| 2 | 销售部 | 一本正经胡说八道部门 || 3 | 财务部 | 花钱太多部门 |+----+-----------+--------------------------------+2 rows in set (0.00 sec)
同步表:
on delete cascade # 同步删除
on update cascade # 同步更新
# 主表内容如下mysql> select * from dep;+----+-----------+--------------------------------+| id | name | descripe |+----+-----------+--------------------------------+| 1 | 技术部 | 各个大牛部们 || 2 | 销售部 | 一本正经胡说八道部门 || 3 | 财务部 | 花钱太多部门 |+----+-----------+--------------------------------+3 rows in set (0.00 sec) # 建立从表mysql> create table emp( -> id int primary key, -> name varchar(20) not null, -> age int not null, -> dep_id int, -> constraint fk_dep foreign key(dep_id) references dep(id) -> on delete cascade # 同步删除 -> on update cascade # 同步更新 -> );Query OK, 0 rows affected (0.08 sec) # 从表插入以下数据mysql> select * from emp;+----+------+-----+--------+| id | name | age | dep_id |+----+------+-----+--------+| 1 | zyk | 19 | 1 || 2 | xhh | 18 | 2 || 3 | jein | 18 | 3 || 4 | egon | 18 | 2 || 5 | lisi | 18 | 3 |+----+------+-----+--------+5 rows in set (0.00 sec) # 同步更新mysql> update dep set id=10 where id=1;Query OK, 1 row affected (0.04 sec)Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from dep;+----+-----------+--------------------------------+| id | name | descripe |+----+-----------+--------------------------------+| 2 | 销售部 | 一本正经胡说八道部门 || 3 | 财务部 | 花钱太多部门 || 10 | 技术部 | 各个大牛部们 |+----+-----------+--------------------------------+3 rows in set (0.00 sec) # 此时可见:与主表关联的dep_id也跟着变化了mysql> select * from emp;+----+------+-----+--------+| id | name | age | dep_id |+----+------+-----+--------+| 1 | zyk | 19 | 10 || 2 | xhh | 18 | 2 || 3 | jein | 18 | 3 || 4 | egon | 18 | 2 || 5 | lisi | 18 | 3 |+----+------+-----+--------+5 rows in set (0.00 sec) # 同步删除mysql> delete from dep where id=3;Query OK, 1 row affected (0.00 sec) mysql> select * from dep;+----+-----------+--------------------------------+| id | name | descripe |+----+-----------+--------------------------------+| 2 | 销售部 | 一本正经胡说八道部门 || 10 | 技术部 | 各个大牛部们 |+----+-----------+--------------------------------+2 rows in set (0.00 sec) # 此时可见:与主表关联的dep_id也被删除了mysql> select * from emp;+----+------+-----+--------+| id | name | age | dep_id |+----+------+-----+--------+| 1 | zyk | 19 | 10 || 2 | xhh | 18 | 2 || 4 | egon | 18 | 2 |+----+------+-----+--------+3 rows in set (0.00 sec)
来源:https://www.cnblogs.com/gqy02/p/11367204.html