一、完整性约束介绍
约束条件与数据类型的宽度一样,都是可选参数
作用:用于保证数据的完整性和一致性
主要分为:
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录 FOREIGN KEY (FK) 标识该字段为该表的外键 NOT NULL 标识该字段不能为空 UNIQUE KEY (UK) 标识该字段的值是唯一的 AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键) DEFAULT 为该字段设置默认值 UNSIGNED 无符号 ZEROFILL 使用0填充
说明:
1. 是否允许为空,默认NULL,可设置NOT NULL,字段不允许为空,必须赋值
2. 字段是否有默认值,缺省的默认值是NULL,如果插入记录时不给字段赋值,此字段使用默认值
sex enum('male','female') not null default 'male'
age int unsigned NOT NULL default 20 必须为正值(无符号) 不允许为空 默认是20
3. 是否是key
主键 primary key
外键 foreign key
索引 (index,unique...)
二、约束条件not null与default
是否可空,null表示空,非字符串
not null - 不可空
null - 可空
默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值
create table tb1(
nid int not null defalut 2,
num int not null
)
==================not null==================== mysql> create table t1(id int); #id字段默认可以插入空 mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+-------+ mysql> insert into t1 values(); #可以插入空 mysql> create table t2(id int not null); #设置字段id不为空 mysql> desc t2; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | +-------+---------+------+-----+---------+-------+ mysql> insert into t2 values(); #不能插入空 ERROR 1364 (HY000): Field 'id' doesn't have a default value ==================default==================== #设置id字段有默认值后,则无论id字段是null还是not null,都可以插入空,插入空默认填入default指定的默认值 mysql> create table t3(id int default 1); mysql> alter table t3 modify id int not null default 1;
mysql> create table t15( -> id int(11) unsigned zerofill # id为字段,必须为字段指定数据类型(int);在数据条件下添加约束条件:unsigned限制id只 能传入无符号 -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc t15 -> ; +-------+---------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------------------+------+-----+---------+-------+ | id | int(11) unsigned zerofill | YES | | NULL | | +-------+---------------------------+------+-----+---------+-------+ 1 row in set (0.00 sec) # not null 不能为空,default设置默认值 mysql> create table t16( -> id int, -> name char(6), -> sex enum('male', 'female') not null default 'male' # 不能为空,传空就用默认值'male' -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc t16; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | char(6) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | +-------+-----------------------+------+-----+---------+-------+ 3 rows in set (0.01 sec) mysql> insert into t16(id,name) values(1,'egon'); Query OK, 1 row affected (0.00 sec) mysql> select * from t16; +------+--------+------+ | id | name | sex | +------+--------+------+ | 1 | egon | male | +------+--------+------+ 1 row in set (0.00 sec)
三、约束条件unique key
unique key指的就是限制字段传入的值是唯一的,不能重复的。
# 创建部门表,且部门名称不设置unique,因此可以创建多个同名部门名称,这明显不合理 mysql> create table department( -> id int, -> name char(10) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc department; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | char(10) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> insert into department values -> (1,'IT'), -> (2,'IT'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from department; +------+------------+ | id | name | +------+------------+ | 1 | IT | | 2 | IT | +------+------------+ 2 rows in set (0.00 sec) # 设置唯一约束unique # 方式一: mysql> drop table department; Query OK, 0 rows affected (0.01 sec) mysql> create table department( -> id int, -> name char(10) unique -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc department; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | char(10) | YES | UNI | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> insert into department values -> (1, 'IT'), -> (2, 'IT'); ERROR 1062 (23000): Duplicate entry 'IT ' for key 'name' # 方式二: mysql> drop table department; Query OK, 0 rows affected (0.01 sec) mysql> create table department( -> id int, -> name char(10), -> unique(id), -> unique(name) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc department; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | UNI | NULL | | | name | char(10) | YES | UNI | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> insert into department values -> (1,'IT'), -> (2,'IT'); ERROR 1062 (23000): Duplicate entry 'IT ' for key 'name' mysql> insert into department values (1,'IT'), (2,'Sale'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> selcet * from department; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'selcet * from department' at line 1 mysql> select * from department; +------+------------+ | id | name | +------+------------+ | 1 | IT | | 2 | Sale | +------+------------+ 2 rows in set (0.00 sec)
mysql> create table services( -> id int, -> ip char(15), -> port int, -> unique(id), # 单列唯一 -> unique(ip,port) # 联合唯一:ip+port唯一 -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc services; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | UNI | NULL | | | ip | char(15) | YES | MUL | NULL | | | port | int(11) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> insert into services values -> (1,'192.168.1.101',80), -> (2,'192.168.1.101',88), -> (3,'192.168.1.103',80); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from services; +------+-----------------+------+ | id | ip | port | +------+-----------------+------+ | 1 | 192.168.1.101 | 80 | | 2 | 192.168.1.101 | 88 | | 3 | 192.168.1.103 | 80 | +------+-----------------+------+ 3 rows in set (0.00 sec) mysql> insert into services values (4,'192.168.1.101',80); ERROR 1062 (23000): Duplicate entry '192.168.1.101 -80' for key 'ip'
四、约束条件primary key
从约束角度看primary key字段的值不为空且唯一(not null unique)。
那直接使用not null+unique不就可以了吗,要primary key干什么?
主键primary key是innodb存储引擎组织数据的依据(innodb称之为索引组织表,对于innodb存储引擎一张表中必须有且只有一个主键)。
一个表中可以:单列做主键、多列做主键(复合主键)
============单列做主键=============== #方法一:not null+unique mysql> create table department( -> id int not null unique, # 主键,通常设置id为主键 -> name varchar(20) not null unique, -> comment varchar(100) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc department; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | NO | UNI | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) #方法二:在某一个字段后用primary key mysql> create table department2( -> id int primary key, # 主键 -> name varchar(20), -> comment varchar(100) -> ); Query OK, 0 rows affected (0.01 sec) 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 | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) # 方法三:在所有字段后单独定义primary key mysql> create table department3( -> id int, -> name varchar(20), -> comment varchar(100), -> constraint pk_name primary key(id) #创建主键并命名为pk_name -> ); Query OK, 0 rows affected (0.02 sec) 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 | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
==================多列做主键================ mysql> create table service( -> ip varchar(15), -> port char(5), -> service_name varchar(10) not null, -> primary key(ip,port) # 多列主键 -> ); Query OK, 0 rows affected (0.01 sec) 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 | | +--------------+-------------+------+-----+---------+-------+ 3 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> select * from service; +--------------+-------+--------------+ | ip | port | service_name | +--------------+-------+--------------+ | 172.16.45.10 | 3306 | mysqld | | 172.16.45.11 | 3306 | mariadb | +--------------+-------+--------------+ 2 rows in set (0.00 sec) mysql> insert into service values ('172.16.45.10', '3306', 'nginx'); ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306 ' for key 'PRIMARY'
总结:只要用的表类型是innodb(最常用),就应该为表指定一个主键,且一般都是指定为id字段。
五、约束条件auto_increment
约束字段为自动增长,被约束的字段必须同时被key约束。
mysql> create table t19( -> id int auto_increment -> ); ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key # 自增长必须是一个key,现在学到的key分为两种:uniqueprimary mysql> create table t19( -> id int unique key auto_increment -> ); Query OK, 0 rows affected (0.02 sec) mysql> desc t19; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | +-------+---------+------+-----+---------+----------------+ 1 row in set (0.00 sec)
#不指定id,则自动增长 mysql> create table student( -> id int primary key auto_increment, -> name varchar(20), -> sex enum('male','female') default 'male' -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc student; +-------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | YES | | male | | +-------+-----------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec) mysql> insert into student(name) values -> ('hqs') -> ,('aelx'), -> ('egon') -> ; Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 1 | hqs | male | | 2 | aelx | male | | 3 | egon | male | +----+------+------+ 3 rows in set (0.00 sec) # 指定id插入 mysql> insert into student values -> (5, 'asb', 'female'); Query OK, 1 row affected (0.01 sec) mysql> insert into student values -> (12, 'zr', 'female'); Query OK, 1 row affected (0.00 sec) mysql> select * from student; +----+------+--------+ | id | name | sex | +----+------+--------+ | 1 | hqs | male | | 2 | aelx | male | | 3 | egon | male | | 5 | asb | female | | 12 | zr | female | +----+------+--------+ 5 rows in set (0.00 sec)
注意:插入指定id的记录后,再插入不指定id记录时,新记录按照最后一条记录的id编码继续往后编排。
1、步长和起始偏移量
mysql> show variables like 'auto_inc%'; # %代表任意个数任意字符 +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1 | # 查到步长,且默认为1 | auto_increment_offset | 1 | # 查到起始偏移量。且默认也为1 +--------------------------+-------+ 2 rows in set (0.02 sec)
设置步长
set session auto_increment_increment=5; # session关键词,说明这个步长修改是会话级别的,只在本次链接有效
set global auto_increment_increment=5; # 修改全局级别的步长,所有会话需要退出后重新连接才生效
#设置步长 sqlserver:自增步长 基于表级别 create table t1( id int。。。 )engine=innodb,auto_increment=2 步长=2 default charset=utf8 mysql自增的步长: show session variables like 'auto_inc%'; #基于会话级别 set session auth_increment_increment=2 #修改会话级别的步长 #基于全局级别的 set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效) #!!!注意了注意了注意了!!! If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 翻译:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略 比如:设置auto_increment_offset=3,auto_increment_increment=2
设置起始偏移量
set global auto_increment_offset=6; # 设置失效,注意:起始偏移量必须小于等于步长
#在创建完表后,修改自增字段的起始值 mysql> create table student( -> id int primary key auto_increment, -> name varchar(20), -> sex enum('male','female') default 'male' -> ); mysql> alter table student auto_increment=3; mysql> show create table student; ....... ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 mysql> insert into student(name) values('egon'); Query OK, 1 row affected (0.01 sec) mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 3 | egon | male | +----+------+------+ row in set (0.00 sec) mysql> show create table student; ....... ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 #也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外 create table student( id int primary key auto_increment, name varchar(20), sex enum('male','female') default 'male' )auto_increment=3;
mysql> show variables like 'auto_incre%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | +--------------------------+-------+ 2 rows in set (0.01 sec) 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> exit # 全局修改后需要退出当前会话 Bye sh-3.2# mysql -uroot -p1234 mysql> show variables like 'auto_in%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 5 | | auto_increment_offset | 3 | +--------------------------+-------+ 2 rows in set (0.00 sec) mysql> use db4 Database changed mysql> create table student1( -> id int primary key auto_increment, -> name varchar(20), -> sex enum('male', 'female') default 'male' -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into student1 -> c mysql> insert into student1(name) values -> ('egon'), -> ('alex'), -> ('hqs'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student1; +----+------+------+ | id | name | sex | +----+------+------+ | 3 | egon | male | | 8 | alex | male | | 13 | hqs | male | +----+------+------+ 3 rows in set (0.00 sec)
2、清空表
方法一:delete from 表名; ——存在的问题:对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长
。
delete更适用于局部记录的删除:delete from t20 where id=3;
方法二:truncate 表名; ——truncate清空表,不同于delete一条一条删除,是直接清空表,删除大表时推荐使用。
mysql> set global auto_increment_increment=1; Query OK, 0 rows affected (0.00 sec) mysql> set global auto_increment_offset=1; Query OK, 0 rows affected (0.00 sec) mysql> exit sh-3.2# mysql -uroot -p1234 # 重新登录,使得新的步长和起始偏移量生效 mysql> select * from student1; +----+------+------+ | id | name | sex | +----+------+------+ | 3 | egon | male | | 8 | alex | male | | 13 | hqs | male | +----+------+------+ 3 rows in set (0.00 sec) mysql> delete from student1; Query OK, 3 rows affected (0.01 sec) mysql> select * from student1; Empty set (0.00 sec) mysql> insert into student1(name) values -> ('asd'); Query OK, 1 row affected (0.00 sec) mysql> select * from student1; +----+------+------+ | id | name | sex | +----+------+------+ | 18 | asd | male | +----+------+------+ 1 row in set (0.00 sec) mysql> show create table student1; +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | student1 | CREATE TABLE `student1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `sex` enum('male','female') DEFAULT 'male', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 | # 可以看到偏移量还是根据之前的id顺延 +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) # 应该用truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它 mysql> truncate student1; Query OK, 0 rows affected (0.02 sec) mysql> show create table student1; +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | student1 | CREATE TABLE `student1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `sex` enum('male','female') DEFAULT 'male', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql> insert into student1(name) values ('egon'), ('alex'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from student1; +----+------+------+ | id | name | sex | +----+------+------+ | 1 | egon | male | # 可以看到已经不依照创表前设置的步长和起始偏移量,按照系统当前的设置执行 | 2 | alex | male | +----+------+------+ 2 rows in set (0.00 sec)
六、约束条件foreign key(外键)
foreign key:用来建立表之间的关系。
以一个公司的员工信息表为例,员工会有id,name,sex,department,comment等字段。但是这样存储会在部门和部门描述上有大量字段重复存储,既浪费空间又不利于后期的维护管理(部门调整或部门改名等)。因此可以把部门和部门相关信息分拆出来,作为部门表。此时部门和员工信息表分开,两者之间完全独立。需要用外键实现两张表关联。
# 1、建立表关系 # 创建失败,因为需要先创建被关联的表 mysql> create table emp( ->id int primary key, ->name char(10), ->sex enum('male', 'female'), ->dep_id int, ->foreign key(dep_id) references dep(id) ->); ERROR 1215 (HY000): Cannot add foreign key constraint # 先建被关联的表,并保证被关联的字段唯一 mysql> create table dep( -> id int primary key, # 或者使用unique,必须保证要关联的字段是惟一的,才能创建关联表 -> name char(16), -> comment char(50) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc dep; +---------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | char(16) | YES | | NULL | | | comment | char(50) | YES | | NULL | | +---------+----------+------+-----+---------+-------+ 3 rows in set (0.00 sec) # 再建关联的表 mysql> create table emp( -> id int primary key, -> name char(10), -> sex enum('male', 'female'), -> dep_id int, -> foreign key(dep_id) references dep(id) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc emp; +--------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | char(10) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | dep_id | int(11) | YES | MUL | NULL | | +--------+-----------------------+------+-----+---------+-------+ 4 rows in set (0.00 sec) # 2、插入数据 # 直接往员工表插入数据,无法插入记录,因为dep_id不能随便写入,必须是被关联内已经具备的数值 mysql> insert into emp values -> (1, 'egon', 'male', '1'); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db1`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`)) # 先往被关联表(dep)插入记录 mysql> insert into dep values -> (1,'IT','技术能力有限部门'), -> (2,'销售','销售能力有限部门'), -> (3,'财务','花钱特别多部门'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from dep; +----+--------+--------------------------+ | id | name | comment | +----+--------+--------------------------+ | 1 | IT | 技术能力有限部门 | | 2 | 销售 | 销售能力有限部门 | | 3 | 财务 | 花钱特别多部门 | +----+--------+--------------------------+ 3 rows in set (0.00 sec) # 再往关联表插入记录 mysql> insert into emp values -> (1, 'egon', 'male', 1), -> (2, 'alex', 'male', 1), -> (3, 'wupeiqi', 'male', 2), -> (4, 'yuanhao', 'male', 3), -> (5, 'jinxin', 'male',2); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from emp; +----+---------+------+--------+ | id | name | sex | dep_id | +----+---------+------+--------+ | 1 | egon | male | 1 | | 2 | alex | male | 1 | | 3 | wupeiqi | male | 2 | | 4 | yuanhao | male | 3 | | 5 | jinxin | male | 2 | +----+---------+------+--------+ 5 rows in set (0.00 sec) # 3、删除数据 # 要删除某个部分,需要先删除子表对应的记录 mysql> delete from emp where dep_id=1; Query OK, 2 rows affected (0.01 sec) mysql> select * from emp; +----+---------+------+--------+ | id | name | sex | dep_id | +----+---------+------+--------+ | 3 | wupeiqi | male | 2 | | 4 | yuanhao | male | 3 | | 5 | jinxin | male | 2 | +----+---------+------+--------+ 3 rows in set (0.00 sec) mysql> delete from dep where id=1; Query OK, 1 row affected (0.00 sec) mysql> select * from dep; +----+--------+--------------------------+ | id | name | comment | +----+--------+--------------------------+ | 2 | 销售 | 销售能力有限部门 | | 3 | 财务 | 花钱特别多部门 | +----+--------+--------------------------+ 2 rows in set (0.00 sec) # 直线先删除父表直接报错 mysql> delete from dep where id=3; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`db1`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`))
上面这种关联关系虽然建立了,但是数据的维护管理其实还是非常繁复。要实现删除(更新)父表,子表对应记录也自动删除(更新),需要在创建关联子表的时候,设置同步删除,同步更新。
create table emp( id int primary key, name char(10), sex enum('male', 'female'), dep_id int, foreign key(dep_id) references dep(id) on delete cascade # 同步删除 on update cascade # 同步更新 );
# 删除所有表 mysql> drop table dep; ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails mysql> drop table emp; Query OK, 0 rows affected (0.01 sec) mysql> drop table dep; Query OK, 0 rows affected (0.00 sec) # 创建被关联的表,且被关联的字段唯一 mysql> create table dep( -> id int primary key, -> name char(16), -> comment char(50) -> ); Query OK, 0 rows affected (0.01 sec) # 再创建关联的表 mysql> create table emp( -> id int primary key, -> name char(10), -> sex enum('male', 'female'), -> dep_id int, -> foreign key(dep_id) references dep(id) -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.01 sec) # 插入数据 mysql> insert into dep values -> (1,'IT','技术能力有限部门'), -> (2,'销售','销售能力有限部门'), -> (3,'财务','花钱特别多部门'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into emp values -> (1,'egon','male',1), -> (2,'alex','male',1), -> (3,'wupeiqi','female',2), -> (4,'yuanhao','male',3), -> (5,'jinxin','male',2); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from dep; +----+--------+--------------------------+ | id | name | comment | +----+--------+--------------------------+ | 1 | IT | 技术能力有限部门 | | 2 | 销售 | 销售能力有限部门 | | 3 | 财务 | 花钱特别多部门 | +----+--------+--------------------------+ 3 rows in set (0.00 sec) mysql> select * from emp; +----+---------+--------+--------+ | id | name | sex | dep_id | +----+---------+--------+--------+ | 1 | egon | male | 1 | | 2 | alex | male | 1 | | 3 | wupeiqi | female | 2 | | 4 | yuanhao | male | 3 | | 5 | jinxin | male | 2 | +----+---------+--------+--------+ 5 rows in set (0.00 sec) # 删除父表,子表emp中对应记录跟着删除 mysql> delete from dep where id=2; Query OK, 1 row affected (0.00 sec) mysql> select * from dep; +----+--------+--------------------------+ | id | name | comment | +----+--------+--------------------------+ | 1 | IT | 技术能力有限部门 | | 3 | 财务 | 花钱特别多部门 | +----+--------+--------------------------+ 2 rows in set (0.00 sec) mysql> select * from emp; +----+---------+------+--------+ | id | name | sex | dep_id | +----+---------+------+--------+ | 1 | egon | male | 1 | | 2 | alex | male | 1 | | 4 | yuanhao | male | 3 | +----+---------+------+--------+ 3 rows in set (0.00 sec) # 更新父表,子表emp中的对应记录跟着修改 mysql> update dep set id=202 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from dep; +-----+--------+--------------------------+ | id | name | comment | +-----+--------+--------------------------+ | 3 | 财务 | 花钱特别多部门 | | 202 | IT | 技术能力有限部门 | +-----+--------+--------------------------+ 2 rows in set (0.00 sec) mysql> select * from emp; +----+---------+------+--------+ | id | name | sex | dep_id | +----+---------+------+--------+ | 1 | egon | male | 202 | | 2 | alex | male | 202 | | 4 | yuanhao | male | 3 | +----+---------+------+--------+ 3 rows in set (0.00 sec)
但是在实际运用中,最好不要通过foreign key直接建立表的耦合关系,考虑程序的扩展性来说,最好是从应用程序里,做两个表的映射关系,两个表只是有逻辑关系。
七、如何找到两张表之间的关系
分析步骤:
(1)先站在左表的角度去找——是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key右表一个字段(通常是id)。
(2)再站在右表的角度去找——是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key左表一个字段(通常是id)。
总结:
多对一:如果只有步骤1成立,则是左表多对一右表
如果只有步骤2成立,则是右表多对一左表
多对多:如果步骤1和步骤2同时成立,证明这两张表示一个双向的多对一,即多对多。需要定义一个这两张表的关系来专门存放二者的关系。
一对一:如果1和2都不成立,而是左表的一条记录唯一对应右表的一条记录,反之亦然。这种情况很简单,就是在左表foreign key右表的基础上,将左表的外键字段设置成unique即可。
八、建立表之间的关系
1、一对多或称多对一
#一对多或称为多对一 三张表:出版社,作者信息,书 一对多(或多对一):一个出版社可以出版多本书 关联方式:foreign key
mysql> create table press( -> id int primary key auto_increment, -> name varchar(20) -> ); Query OK, 0 rows affected (0.01 sec) mysql> create table book( -> id int primary key auto_increment, -> name varchar(20), -> press_id int not null, -> foreign key(press_id) references press(id) -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into press(name) values -> ('北京工业地雷出版社'), -> ('人民音乐不好听出版社'), -> ('知识产权没有用出版社') -> ; Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into book(name,press_id) values -> ('九阳神功',1), -> ('九阴真经',2), -> ('九阴白骨爪',2), -> ('独孤九剑',3), -> ('降龙十巴掌',2), -> ('葵花宝典',3) -> ; Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> select * from press; +----+--------------------------------+ | id | name | +----+--------------------------------+ | 1 | 北京工业地雷出版社 | | 2 | 人民音乐不好听出版社 | | 3 | 知识产权没有用出版社 | +----+--------------------------------+ 3 rows in set (0.00 sec) mysql> select * from book; +----+-----------------+----------+ | id | name | press_id | +----+-----------------+----------+ | 1 | 九阳神功 | 1 | | 2 | 九阴真经 | 2 | | 3 | 九阴白骨爪 | 2 | | 4 | 独孤九剑 | 3 | | 5 | 降龙十巴掌 | 2 | | 6 | 葵花宝典 | 3 | +----+-----------------+----------+ 6 rows in set (0.00 sec)
2、多对多
#多对多 三张表:出版社,作者信息,书 多对多:一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多 关联方式:foreign key+一张新的表
多对多的情况下,无法像多对一一样,多设置一个对应字段并设置为外键。必须创一个存放两者关系的表,一个字段关联左表id,一个字段关联右表id,这样就解决了多对多的问题。
mysql> select * from book; +----+-----------------+----------+ | id | name | press_id | +----+-----------------+----------+ | 1 | 九阳神功 | 1 | | 2 | 九阴真经 | 2 | | 3 | 九阴白骨爪 | 2 | | 4 | 独孤九剑 | 3 | | 5 | 降龙十巴掌 | 2 | | 6 | 葵花宝典 | 3 | +----+-----------------+----------+ 6 rows in set (0.00 sec) mysql> mysql> mysql> mysql> mysql> create table author( -> id int primary key auto_increment, -> name varchar(20) -> ); Query OK, 0 rows affected (0.02 sec) #这张表就存放作者表与书表的关系,即查询二者的关系查这表就可以了 mysql> create table author2book( -> id int not null unique auto_increment, -> author_id int not null, -> book_id int not null, -> constraint fk_author foreign key(author_id) references author(id) # constraint为外键取名fk_author -> on delete cascade -> on update cascade, -> constraint fk_book foreign key(book_id) references book(id) # book_id关联book表的id字段 -> on delete cascade -> on update cascade, -> primary key(author_id,book_id) -> ); Query OK, 0 rows affected (0.02 sec) #每个作者与自己的代表作如下 1 egon: 1 九阳神功 2 九阴真经 3 九阴白骨爪 4 独孤九剑 5 降龙十巴掌 6 葵花宝典 2 alex: 1 九阳神功 6 葵花宝典 3 yuanhao: 4 独孤九剑 5 降龙十巴掌 6 葵花宝典 4 wpq: 1 九阳神功 mysql> #插入四个作者,id依次排开 mysql> insert into author(name) values('egon'),('alex'),('yuanhao'),('wpq'); Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 # 写入作者、书籍对应关系 mysql> insert into author2book(author_id,book_id) values -> (1,1), -> (1,2), -> (1,3), -> (1,4), -> (1,5), -> (1,6), -> (2,1), # alex,九阳神功 -> (2,6), -> (3,4), # yuanhao,独孤九剑 -> (3,5), -> (3,6), -> (4,1); # wpq,九阳神功 Query OK, 12 rows affected (0.01 sec) Records: 12 Duplicates: 0 Warnings: 0 mysql> select * from author2book; +----+-----------+---------+ | id | author_id | book_id | +----+-----------+---------+ | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 1 | 3 | | 4 | 1 | 4 | | 5 | 1 | 5 | | 6 | 1 | 6 | | 7 | 2 | 1 | | 8 | 2 | 6 | | 9 | 3 | 4 | | 10 | 3 | 5 | | 11 | 3 | 6 | | 12 | 4 | 1 | +----+-----------+---------+ 12 rows in set (0.00 sec)
3、一对一
#一对一 两张表:学生表和客户表 一对一:一个学生是一个客户,一个客户有可能变成一个学校,即一对一的关系 关联方式:foreign key+unique
分析学生和客户的关系,学生一定是一个客户,客户不是学生,但有可能成为一个学生。因此必须用student来foreign key 表customer。
# 先建立客户表,学生来自客户 mysql> create table customer( -> id int primary key auto_increment, -> name varchar(20) not null, -> qq varchar(10) not null, -> phone char(16) not null -> ); Query OK, 0 rows affected (0.01 sec) # 建立学生表 mysql> create table student( -> id int primary key auto_increment, # 学号 -> class_name varchar(20) not null, # 班级 -> customer_id int unique, # 该字段一定要是唯一的,加了unique则学生和客户一一对应 -> foreign key(customer_id) references customer(id) # 这张表的customer_id关联客户表的id字段 -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.02 sec) # 增加客户 mysql> insert into customer(name,qq,phone) values ('李飞机','31811231',13811341220), ('王大炮','123123123',15213146809), -> ('李飞机','31811231',13811341220), -> ('王大炮','123123123',15213146809), -> ('守榴弹','283818181',1867141331), ('守榴弹','283818181',1867141331), -> ('吴坦克','283818181',1851143312), -> ('赢火箭','888818181',1861243314), -> ('战地雷','112312312',18811431230) -> ; Query OK, 6 rows affected (0.01 sec) Records: 6 Duplicates: 0 Warnings: 0 #增加学生 mysql> insert into student(class_name,customer_id) values -> ('脱产3班',3), -> ('周末19期',4), -> ('周末19期',5) -> ; Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from customer; +----+-----------+-----------+-------------+ | id | name | qq | phone | +----+-----------+-----------+-------------+ | 1 | 李飞机 | 31811231 | 13811341220 | | 2 | 王大炮 | 123123123 | 15213146809 | | 3 | 守榴弹 | 283818181 | 1867141331 | | 4 | 吴坦克 | 283818181 | 1851143312 | | 5 | 赢火箭 | 888818181 | 1861243314 | | 6 | 战地雷 | 112312312 | 18811431230 | +----+-----------+-----------+-------------+ 6 rows in set (0.00 sec) mysql> select * from student; +----+-------------+-------------+ | id | class_name | customer_id | +----+-------------+-------------+ | 1 | 脱产3班 | 3 | | 2 | 周末19期 | 4 | | 3 | 周末19期 | 5 | +----+-------------+-------------+ 3 rows in set (0.00 sec)
例一:一个用户只有一个博客 用户表: id name 1 egon 2 alex 3 wupeiqi 博客表 fk+unique id url name_id 1 xxxx 1 2 yyyy 3 3 zzz 2 例二:一个管理员唯一对应一个用户 用户表: id user password 1 egon xxxx 2 alex yyyy 管理员表: fk+unique id user_id password 1 1 xxxxx 2 2 yyyyy
九、练习和作业
练习:账号信息表,用户组,主机表,主机组。
#用户表 create table user( id int not null unique auto_increment, username varchar(20) not null, password varchar(50) not null, primary key(username,password) ); insert into user(username,password) values ('root','123'), ('egon','456'), ('alex','alex3714') ; #用户组表 create table usergroup( id int primary key auto_increment, groupname varchar(20) not null unique ); insert into usergroup(groupname) values ('IT'), ('Sale'), ('Finance'), ('boss') ; #主机表 create table host( id int primary key auto_increment, ip char(15) not null unique default '127.0.0.1' ); insert into host(ip) values ('172.16.45.2'), ('172.16.31.10'), ('172.16.45.3'), ('172.16.31.11'), ('172.10.45.3'), ('172.10.45.4'), ('172.10.45.5'), ('192.168.1.20'), ('192.168.1.21'), ('192.168.1.22'), ('192.168.2.23'), ('192.168.2.223'), ('192.168.2.24'), ('192.168.3.22'), ('192.168.3.23'), ('192.168.3.24') ; #业务线表 create table business( id int primary key auto_increment, business varchar(20) not null unique ); insert into business(business) values ('轻松贷'), ('随便花'), ('大富翁'), ('穷一生') ; #建关系:user与usergroup create table user2usergroup( id int not null unique auto_increment, user_id int not null, group_id int not null, primary key(user_id,group_id), foreign key(user_id) references user(id), foreign key(group_id) references usergroup(id) ); insert into user2usergroup(user_id,group_id) values (1,1), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4) ; #建关系:host与business create table host2business( id int not null unique auto_increment, host_id int not null, business_id int not null, primary key(host_id,business_id), foreign key(host_id) references host(id), foreign key(business_id) references business(id) ); insert into host2business(host_id,business_id) values (1,1), (1,2), (1,3), (2,2), (2,3), (3,4) ; #建关系:user与host create table user2host( id int not null unique auto_increment, user_id int not null, host_id int not null, primary key(user_id,host_id), foreign key(user_id) references user(id), foreign key(host_id) references host(id) ); insert into user2host(user_id,host_id) values (1,1), (1,2), (1,3), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,10), (1,11), (1,12), (1,13), (1,14), (1,15), (1,16), (2,2), (2,3), (2,4), (2,5), (3,10), (3,11), (3,12) ;
# 创建用户表 mysql> create table user( -> id int not null unique auto_increment, # 用户的id非空、唯一且自增 -> username varchar(20) not null, -> password varchar(50) not null, -> primary key(username,password) # 复合主键:用户名+密码 -> ); Query OK, 0 rows affected (0.03 sec) # 插入用户数据 mysql> insert into user(username,password) values -> ('root', '123'), -> ('egon', '456'), -> ('alex', 'alex3714') -> ; Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from user; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | root | 123 | | 2 | egon | 456 | | 3 | alex | alex3714 | +----+----------+----------+ 3 rows in set (0.00 sec) # 创建用户组 mysql> create table usergroup( -> id int primary key auto_increment, # 用户组id设为主键,且自增 -> groupname varchar(20) not null unique # 用户组名非空且唯一 -> ); Query OK, 0 rows affected (0.03 sec) # 插入用户组数据 mysql> insert into usergroup(groupname) values -> ('IT'), -> ('Sale'), -> ('Finance'), -> ('boss') -> ; Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from usergroup; +----+-----------+ | id | groupname | +----+-----------+ | 4 | boss | | 3 | Finance | | 1 | IT | | 2 | Sale | +----+-----------+ 4 rows in set (0.00 sec) # 创建主机表 mysql> create table host( -> id int primary key auto_increment, # 主机表id为主键、自增 -> ip char(15) not null unique default '127.0.0.1' # ip地址非空、唯一、设置了默认值 -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into host(ip) values -> ('172.16.45.2'), -> ('172.16.31.10'), -> ('172.16.45.3'), -> ('172.16.31.11'), -> ('172.10.45.3'), -> ('172.10.45.4'), -> ('172.10.45.5'), -> ('192.168.1.20'), -> ('192.168.1.21'), -> ('192.168.1.22'), -> ('192.168.2.23'), -> ('192.168.2.223'), -> ('192.168.2.24'), -> ('192.168.3.22'), -> ('192.168.3.23'), -> ('192.168.3.24') -> ; Query OK, 16 rows affected (0.00 sec) Records: 16 Duplicates: 0 Warnings: 0 mysql> select * from host; +----+---------------+ | id | ip | +----+---------------+ | 5 | 172.10.45.3 | | 6 | 172.10.45.4 | | 7 | 172.10.45.5 | | 2 | 172.16.31.10 | | 4 | 172.16.31.11 | | 1 | 172.16.45.2 | | 3 | 172.16.45.3 | | 8 | 192.168.1.20 | | 9 | 192.168.1.21 | | 10 | 192.168.1.22 | | 12 | 192.168.2.223 | | 11 | 192.168.2.23 | | 13 | 192.168.2.24 | | 14 | 192.168.3.22 | | 15 | 192.168.3.23 | | 16 | 192.168.3.24 | +----+---------------+ 16 rows in set (0.00 sec) # 创建业务表 mysql> create table business( -> id int primary key auto_increment, # 业务id为主键、自增 -> business varchar(20) not null unique # 业务非空、唯一 -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into business(business) values -> ('轻松贷'), -> ('随便花'), -> ('大富翁'), -> ('穷一生') -> ; Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from business; +----+-----------+ | id | business | +----+-----------+ | 3 | 大富翁 | | 4 | 穷一生 | | 1 | 轻松贷 | | 2 | 随便花 | +----+-----------+ 4 rows in set (0.00 sec) # 建关系:user和usergroup 多对多 mysql> create table user2usergroup( -> id int not null unique auto_increment, -> user_id int not null, -> group_id int not null, -> primary key(user_id, group_id), # 指定并创建复合主键、约束为不为空且唯一 -> foreign key(user_id) references user(id), # user_id关联用户表id字段 -> foreign key(group_id) references usergroup(id) # group_id关联用户组id字段 -> ); Query OK, 0 rows affected (0.03 sec) mysql> insert into user2usergroup(user_id,group_id) values -> (1,1), -> (1,2), -> (1,3), -> (1,4), -> (2,3), -> (2,4), -> (3,4) -> ; Query OK, 7 rows affected (0.00 sec) Records: 7 Duplicates: 0 Warnings: 0 mysql> select * from user2usergroup; +----+---------+----------+ | id | user_id | group_id | +----+---------+----------+ | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 1 | 3 | | 4 | 1 | 4 | | 5 | 2 | 3 | | 6 | 2 | 4 | | 7 | 3 | 4 | +----+---------+----------+ 7 rows in set (0.00 sec) # 建关系:host与business 多对多 mysql> create table host2business( -> id int not null unique auto_increment, -> host_id int not null, -> business_id int not null, -> primary key(host_id,business_id), # 指定并创建复合主键、约束为不为空且唯一 -> foreign key(host_id) references host(id), # host_id关联用户id字段 -> foreign key(business_id) references business(id) # business_id关联业务id字段 -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into host2business(host_id, business_id) values -> (1,1), -> (1,2), -> (1,3), -> (2,2), -> (2,3), -> (3,4); Query OK, 6 rows affected (0.01 sec) Records: 6 Duplicates: 0 Warnings: 0 # 建关系:user与host 多对多 mysql> create table user2host( -> id int not null unique auto_increment, -> user_id int not null, -> host_id int not null, -> primary key(user_id,host_id), -> foreign key(user_id) references user(id), # user_id关联用户id字段 -> foreign key(host_id) references host(id) # host_id关联主机id字段 -> ); Query OK, 0 rows affected (0.03 sec) mysql> insert into user2host(user_id,host_id) values -> (1,1), -> (1,2), -> (1,3), -> (1,4), -> (1,5), -> (1,6), -> (1,7), -> (1,8), -> (1,9), -> (1,10), -> (1,11), -> (1,12), -> (1,13), -> (1,14), -> (1,15), -> (1,16), -> (2,2), -> (2,3), -> (2,4), -> (2,5), -> (3,10), -> (3,11), -> (3,12) -> ; Query OK, 23 rows affected (0.00 sec) Records: 23 Duplicates: 0 Warnings: 0
作业:
mysql> create database db2; Query OK, 1 row affected (0.00 sec) mysql> use db2 Database changed mysql> show tables; Empty set (0.00 sec) mysql> create table class( -> cid int primary key auto_increment, -> caption char(20) not null -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into class(caption) values -> ('三年二班'), -> ('一年三班'), -> ('三年一班'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from class; +-----+--------------+ | cid | caption | +-----+--------------+ | 1 | 三年二班 | | 2 | 一年三班 | | 3 | 三年一班 | +-----+--------------+ 3 rows in set (0.00 sec) mysql> create table student( -> sid int primary key auto_increment, -> sname char(20) not null, -> gender enum('男','女') not null, -> class_id int not null, -> foreign key(class_id) references class(cid) -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into student(sname,gender,class_id) values -> ('钢蛋','女',1), -> ('铁锤','女',1), -> ('山炮','男',2); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student; +-----+--------+--------+----------+ | sid | sname | gender | class_id | +-----+--------+--------+----------+ | 1 | 钢蛋 | 女 | 1 | | 2 | 铁锤 | 女 | 1 | | 3 | 山炮 | 男 | 2 | +-----+--------+--------+----------+ 3 rows in set (0.00 sec) mysql> create table teacher( -> tid int primary key auto_increment, -> tname char(20) not null -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into teacher(tname) values -> ('波多'), -> ('苍空'), -> ('饭岛'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from teacher; +-----+--------+ | tid | tname | +-----+--------+ | 1 | 波多 | | 2 | 苍空 | | 3 | 饭岛 | +-----+--------+ 3 rows in set (0.00 sec) mysql> create table course( -> cid int primary key auto_increment, -> cname char(20) not null, -> teacher_id int not null, -> foreign key(teacher_id) references teacher(tid) -> on delete cascade -> on update cascade -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into course(cname,teacher_id) values -> ('生物',1),('体育',1),('物理',2); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from course; +-----+--------+------------+ | cid | cname | teacher_id | +-----+--------+------------+ | 1 | 生物 | 1 | | 2 | 体育 | 1 | | 3 | 物理 | 2 | +-----+--------+------------+ 3 rows in set (0.00 sec) mysql> create table score( -> sid int not null unique auto_increment, -> student_id int not null, -> corse_id int not null, -> foreign key(student_id) references student(sid) -> on delete cascade -> on update cascade, -> foreign key(corse_id) references course(cid) -> on delete cascade -> on update cascade, -> number int not null, -> primary key(student_id, corse_id) -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into score(student_id, corse_id, number) values -> (1,1,60),(1,2,59),(2,2,100); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from score; +-----+------------+----------+--------+ | sid | student_id | corse_id | number | +-----+------------+----------+--------+ | 1 | 1 | 1 | 60 | | 2 | 1 | 2 | 59 | | 3 | 2 | 2 | 100 | +-----+------------+----------+--------+ 3 rows in set (0.00 sec)