约束,就是用来保证数据完整性和一致性的。
常见的约束分为:
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录
FOREIGN KEY (FK) 标识该字段为该表的外键
NOT NULL 标识该字段不能为空
UNIQUE KEY (UK) 标识该字段的值是唯一的
AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键)
DEFAULT 为该字段设置默认值
UNSIGNED 无符号
ZEROFILL 使用0填充
下面会说其中的一部分
unique 唯一索引
使用方式
============设置唯一约束 UNIQUE=============== 方法一: create table department1( id int, name varchar(20) unique, comment varchar(100) ); 方法二: create table department2( id int, name varchar(20), comment varchar(100), constraint uk_name unique(name) ); mysql> insert into department1 values(1,'IT','技术'); Query OK, 1 row affected (0.00 sec) mysql> insert into department1 values(1,'IT','技术'); ERROR 1062 (23000): Duplicate entry 'IT' for key 'name'
如果是not null和unique进行组合的话,会变成主键
mysql> create table t1(id int not null unique); Query OK, 0 rows affected (0.02 sec) mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | +-------+---------+------+-----+---------+-------+ row in set (0.00 sec)
create table service( id int primary key auto_increment, name varchar(20), host varchar(15) not null, port int not null, unique(host,port) #联合唯一 ); mysql> insert into service values -> (1,'nginx','192.168.0.10',80), -> (2,'haproxy','192.168.0.20',80), -> (3,'mysql','192.168.0.30',3306) -> ; Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into service(name,host,port) values('nginx','192.168.0.10',80); ERROR 1062 (23000): Duplicate entry '192.168.0.10-80' for key 'host' 联合唯一
primary key主键
从约束角度看primary key字段的值不为空且唯一,那我们直接使用not null+unique不就可以了吗,要它干什么?
innodb称之为索引组织表,一张表中必须有且只有一个主键。主键primary key是innodb存储引擎组织数据的依据。
一个表中可以有两种形式:
- 单列做主键
- 多列做主键(复合主键)
============单列做主键=============== #方法一:not null+unique create table department1( id int not null unique, #主键 name varchar(20) not null unique, comment varchar(100) ); mysql> desc department1; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | NO | UNI | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.01 sec) #方法二:在某一个字段后用primary key create table department2( id int primary key, #主键 name varchar(20), comment varchar(100) ); mysql> desc department2; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.00 sec) #方法三:在所有字段后单独定义primary key create table department3( id int, name varchar(20), comment varchar(100), constraint pk_name primary key(id); #创建主键并为其命名pk_name mysql> desc department3; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.01 sec)
==================多列做主键================ create table service( ip varchar(15), port char(5), service_name varchar(10) not null, primary key(ip,port) ); mysql> desc service; +--------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+-------+ | ip | varchar(15) | NO | PRI | NULL | | | port | char(5) | NO | PRI | NULL | | | service_name | varchar(10) | NO | | NULL | | +--------------+-------------+------+-----+---------+-------+ rows in set (0.00 sec) mysql> insert into service values -> ('172.16.45.10','3306','mysqld'), -> ('172.16.45.11','3306','mariadb') -> ; Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into service values ('172.16.45.10','3306','nginx'); ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY' 多列主键
auto_increment自增
这里对使用自增做几点说明
- 给字段设置自增之后,还是可以给该字段赋值的
- 如果用delete删除了记录后,再插入值,该字段仍按照删除前的位置继续增长
- truncate是清空表,而delete是一条条的删记录,当用truncate清空表中之后,设置的自增的字段重新从1开始自增。
# auto_increment_increment这是自增长的步长。 # auto_increment_offset这是自增长开始的值 #基于会话级别 #比如:set session auth_increment_increment=2 #修改会话级别的步长 #基于全局级别的 #比如:set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效) 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_incre%'; #需要退出重新登录 +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | +--------------------------+-------+
foreign key 外键
为什么会产生外键,举个例子:
员工信息表有三个字段:工号 姓名 部门
公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费
解决方法:
我们完全可以定义一个部门表
然后让员工信息表关联该表,如何关联,即foreign key
使用外键要注意的:
- 表的类型必须是innodb存储引擎
- 被关联的字段,也就是另一个表中的字段,必须保证唯一。
外键的定义语法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...) REFERENCES tbl_name (index_col_name, ...) [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}] [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
说明:
该语法可以在 CREATE TABLE 和 ALTER TABLE 时使用,
CONSTRAINT symbol,是给这个约束增加一个名字,如果不指定MYSQL会自动生成一个名字。
ON DELETE、ON UPDATE表示事件触发限制,可设参数:
RESTRICT(限制外表中的外键改动)
CASCADE(跟随外键改动)
SET NULL(设空值)
SET DEFAULT(设默认值)
NO ACTION(无动作,默认的)
例子:
说明,这个例子是在网上看到的,虽然有些说明不好,但比较有条理而且易于理解的,原文地址为:http://www.cppblog.com/wolf/articles/69089.html
# 创建两张表,一个是大哥表,一个小弟表,大哥表的id是小弟表的外键。 CREATE TABLE `dage` ( `id` int(11) NOT NULL auto_increment, `name` varchar(32) default '', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `xiaodi` ( `id` int(11) NOT NULL auto_increment, `dage_id` int(11) default NULL, `name` varchar(32) default '', PRIMARY KEY (`id`), KEY `dage_id` (`dage_id`), CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; # 大哥表中插入一个记录 mysql> insert into dage(name) values('铜锣湾'); Query OK, 1 row affected (0.01 sec) mysql> select * from dage; +----+--------+ | id | name | +----+--------+ | 1 | 铜锣湾 | +----+--------+ 1 row in set (0.00 sec) # 小弟表中插入一个记录 mysql> insert into xiaodi(dage_id,name) values(1,'铜锣湾_小弟A'); Query OK, 1 row affected (0.02 sec) mysql> select * from xiaodi; +----+---------+--------------+ | id | dage_id | name | +----+---------+--------------+ | 1 | 1 | 铜锣湾_小弟A | +----+---------+--------------+ # 想要删除大哥中的一个记录,这个时候会提示,这个大哥是一个小弟的外键,不让删 mysql> delete from dage where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`bstar/xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)) # 这个时候给大哥的外键约束增加时间触发限制 mysql> show create table xiaodi; ... CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`) ... mysql> alter table xiaodi drop foreign key xiaodi_ibfk_1; Query OK, 1 row affected (0.04 sec) Records: 1 Duplicates: 0 Warnings: mysql> alter table xiaodi add foreign key(dage_id) references dage(id) on delete cascade on update cascade; Query OK, 1 row affected (0.04 sec) Records: 1 Duplicates: 0 Warnings: 0 # 然后再删大哥 mysql> delete from dage where id=1; Query OK, 1 row affected (0.01 sec) mysql> select * from dage; Empty set (0.01 sec) mysql> select * from xiaodi; Empty set (0.00 sec) # 这个时候大哥和小弟就都被一套带走了。