首页 > 技术文章 > 表与表关系

KbMan 2019-08-20 19:44 原文

外键

什么是外键:让表与表有硬性层面上的关系

使用外键条件:1、表类型必须是InnoDB存储引擎。2、关联的字段即references指定的另外一个表的字段必须要唯一。

注意:1、创建表时必须先创建被关联表。2、插入数据时,也必须先插入被关联表数据。

一对多

案例1:部门和员工

思考:

  • 一个部门可以有多个员工吗?可以
  • 一个员工可以有多个部门吗?不可以
  • 结论:部门与员工的关系是一对多。且外键创建在多的一方。

案例二:班级和学生

  • 一个班级可以有多个学生吗?可以
  • 一个学生可以有多个班级吗?不可以
  • 结论:一对多,外键建立在多的一方即学生表里面。

案例三:老师和课程

  • 一个课程可以有多个老师吗?可以。
  • 一个老师可以有多个课程吗?不可以,一个老师只能教一门课程,语文老师不能同时也是数学老师,不专业。
  • 结论:一对多,老师表里面应该设置外键。

只有一方可以一条数据对应对方的多条数据,这种关系叫做一对多。

'''
创建部门表:
'''
create table department(
	id int primary key auto_increment,
    name varchar(20) not null,
    dep_desc varchar(200)
);

'''
创建员工表
'''
create table employee(
	id int primary key auto_increment,
    name varchar(20) not null,
    gender enum('male', 'female', 'others') default 'male',
    department_id int,
    foreign key(department_id) references department(id)
    on update cascade 
	on delete cascade
);

'''
插入数据
''’
insert into department(name, dep_desc) values('技术部', '技术部都是一群菜*');
insert into employee(name, gender, department_id) values('游哥', 'male', 1);

同步更新与同步删除:更新和删除操作都需要考虑关联与被关联的关系。这时候,出现级联操作

on update cascade

on delete cascade

删除部门后,对应的部门里面的员工表数据对应删除

更新部门后,对应员工表中的标示部门的字段同步更新

多对多

案例一:图书和作者

分析:

  • 一本图书可以有多个作者吗?可以
  • 一个作者可以有多本书吗? 完全可以!
  • 结论:多对多,需要建立中间表。

案例二:老师和学生

  • 一个老师可以有多个学生吗?可以
  • 一个学生可以有多个老师吗?可以
  • 结论:多对多

双方都能一条数据对应对方的多条数据,这种关系叫做多对多。

=====================创建表=================
mysql> create table author(
    -> id int primary key auto_increment,
    -> name varchar(20));
Query OK, 0 rows affected (0.03 sec)

mysql> create table book(
    -> id int primary key auto_increment,
    -> name varchar(20));
Query OK, 0 rows affected (0.03 sec)

mysql> create table author_book(
    -> id int primary key auto_increment,
    -> author_id int,
    -> book_id int,
    -> foreign key(author_id) references author(id)
    -> on update cascade
    -> on delete cascade,
    -> foreign key(book_id) references book(id)
    -> on update cascade
    -> on delete cascade);
Query OK, 0 rows affected (0.02 sec)

=====================表详情=================
mysql> desc author_book;
+-----------+---------+------+-----+---------+----------------+
| Field     | Type    | Null | Key | Default | Extra          |
+-----------+---------+------+-----+---------+----------------+
| id        | int(11) | NO   | PRI | NULL    | auto_increment |
| author_id | int(11) | YES  | MUL | NULL    |                |
| book_id   | int(11) | YES  | MUL | NULL    |                |
+-----------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc author;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> desc book;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

==============================插入数据===================

mysql> insert into author(name) values('游哥');
Query OK, 1 row affected (0.00 sec)

mysql> insert into author(name) values('鸡弟弟');
Query OK, 1 row affected (0.00 sec)

mysql> insert into book(name) values('金瓶11111');
Query OK, 1 row affected (0.00 sec)

mysql> insert into book(name) values('Python从入门到放弃');
Query OK, 1 row affected (0.00 sec)

mysql> insert into author_book(author_id, book_id) values(1,1),(1,2),(2,1);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from author_book;
+----+-----------+---------+
| id | author_id | book_id |
+----+-----------+---------+
|  1 |         1 |       1 |
|  2 |         1 |       2 |
|  3 |         2 |       1 |
+----+-----------+---------+
3 rows in set (0.00 sec)

一对一

左表的一条记录唯一对应右表的一条记录,反之也一样。

格式:foreign key + unique

案例一:一个用户只有一个博客

create table user(
	id int primary key auto_increment,
    name varchar(20)
);

create table blog(
	id int primary key auto_increment,
    blog_addr varchar(100),
    user_id int unique,
    foreign key(user_id) references user(id)
);

mysql> desc blog;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| blog_addr | varchar(100) | YES  |     | NULL    |                |
| user_id   | int(11)      | YES  | UNI | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> insert into user(
    -> name) values('游哥');
Query OK, 1 row affected (0.00 sec)

mysql> insert into blog(blog_addr, user_id) values('上海', 1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into blog(blog_addr, user_id) values('上海', 1);
ERROR 1062 (23000): Duplicate entry '1' for key 'user_id'
mysql> select * from blog;
+----+-----------+---------+
| id | blog_addr | user_id |
+----+-----------+---------+
|  1 | 上海      |       1 |
+----+-----------+---------+
1 row in set (0.00 sec)

修改表

1. 修改表名 
	ALTER TABLE 表名 RENAME 新表名;
	alter table user rename userinfo;
2. 增加字段
      ALTER TABLE 表名
                      ADD 字段名  数据类型 [完整性约束条件…],
         			  ADD 字段名  数据类型 [完整性约束条件…];
        mysql> alter table userinfo add gender enum('male', 'female') default 'male';
        mysql> desc userinfo;
        +--------+-----------------------+------+-----+---------+----------------+
        | Field  | Type                  | Null | Key | Default | Extra          |
        +--------+-----------------------+------+-----+---------+----------------+
        | id     | int(11)               | NO   | PRI | NULL    | auto_increment |
        | name   | varchar(20)           | YES  |     | NULL    |                |
        | gender | enum('male','female') | YES  |     | male    |                |
        +--------+-----------------------+------+-----+---------+----------------+

      ALTER TABLE 表名
                      ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
      ALTER TABLE 表名
                      ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名; 
                      
3. 删除字段
      ALTER TABLE 表名 DROP 字段名;
      mysql> alter table userinfo drop gender;
      
4. 修改字段  # modify只能改字段数据类型完整约束,不能改字段名,但是change可以!
      ALTER TABLE 表名 
                          MODIFY  字段名 数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];

复制表

# 查询语句执行的结果也是一张表,可以看成虚拟表

# 复制表结构+记录 (key不会复制: 主键、外键和索引)
create table new_service select * from service;

# 只复制表结构
select * from service where 1=2;        //条件为假,查不到任何记录

create table new1_service select * from service where 1=2;  

create table t4 like employees;

mysql> create table user(
    -> id int primary key auto_increment,
    -> name varchar(10));
Query OK, 0 rows affected (0.03 sec)

mysql> create table userinfo like user;
Query OK, 0 rows affected (0.02 sec)

mysql> desc userinfo;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> desc user;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

推荐阅读