首页 > 其他分享 >约束条件之主键、外键、表关系之一对一、一对多、多对多

约束条件之主键、外键、表关系之一对一、一对多、多对多

时间:2022-08-16 20:11:37浏览次数:55  
标签:约束条件 name int 外键 id dep key mysql 主键

约束条件之主键

primary key 称之为主键

特点

1.单从约束角度上而言主键等价于非空且唯一(not null unique)

mysql> create table t1(id int primary key,name varchar(32));
Query OK, 0 rows affected (0.04 sec)

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

mysql> insert into t1 values(1,'nana');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,'aa');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> select * from t1;
+----+------+
| id | name |
+----+------+
|  1 | nana |
+----+------+
1 row in set (0.00 sec)

2.InnoDB存储引擎规定一张表必须有且只有一个主键(主键可以加快数据的查询)

1.如果创建的表中没有主键也没有非空且唯一的字段,那么InnoDB存储引擎会自动采用一个隐藏的字段作为组件
2.如果创建的表没有主键但是有非空且唯一的字段,那么InnoDB存储引擎会自动将该字段设置为主键

eg:
mysql> create table t2(id int not null unique,name varchar(32));
Query OK, 0 rows affected (0.03 sec)

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

mysql> insert into t2 values(1,'nana');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t2 values(1,'aa');
ERROR 1062 (23000): Duplicate entry '1' for key 'id'

3.创建表的时候应该有一个‘id'字段(该字段名非固定),并且该字段应该作为主键

4.创建表可以使用单列主键,也可以使用联合组件

mysql> create table t3(id int, nid int,primary key(id,nid));
Query OK, 0 rows affected (0.04 sec)

mysql> insert into t3 values(1,2);
Query OK, 1 row affected (0.00 sec)

mysql> insert into t3 values(1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t3 values(1,2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'PRIMARY'

约束条件之自增

auto_increment 称之为自增,该约束条件不能单独使用 必须跟在键后面(主要配合主键一起使用)

mysql> create table t4(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

mysql> create table t4(id int primary key auto_increment,name varchar(32));
Query OK, 0 rows affected (0.04 sec)

mysql> desc t4;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(32) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

mysql> insert into t4(name) values('nana'),('aa'),('bb'),('cc');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from t4;
+----+------+
| id | name |
+----+------+
|  1 | nana |
|  2 | aa   |
|  3 | bb   |
|  4 | cc   |
+----+------+

特点

自增的操作不会因为执行删除数据的操作而回退或者重置

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

mysql> insert into t5(name) values('aa'),('bb'),('cc'),('dd');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from t5;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
|  3 | cc   |
|  4 | dd   |
+----+------+
4 rows in set (0.00 sec)

mysql> delete from t5 where id=4;
Query OK, 1 row affected (0.01 sec)

mysql> select * from t5;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
|  3 | cc   |
+----+------+
3 rows in set (0.00 sec)

mysql> insert into t5(name) values('ee'),('ff');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from t5;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
|  3 | cc   |
|  5 | ee   |
|  6 | ff   |
+----+------+
5 rows in set (0.00 sec)

如果非要重置主键 需要格式化表 : truncate 表名; 代表删除表数据并重置主键值

mysql> truncate t5;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from t5;
Empty set (0.00 sec)

mysql> insert into t5(name) values('aa'),('bb'),('cc'),('dd');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from t5;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
|  3 | cc   |
|  4 | dd   |
+----+------+
4 rows in set (0.00 sec)

约束条件之外键

外键知识导入

需求:创建一张员工表

id name gender dep_name dep_desc
1 jason male 讲师部门 传授知识
2 kevin male 财务部门 管理财务
3 tony male 财务部门 管理财务

上述表的缺陷

1.表结构不清晰,到底是员工表还是部门表不清楚
2.字段数据反复存取,浪费存储空间
3.表的扩展性极差,牵以发动全身

优化操作:拆表

id name gender
1 jason male
2 kevin male
3 tony male
id dep_name dep_desc
1 讲师部门 传授知识
2 财务部门 管理财务

拆表之后解决了上述的三个问题,但是出现了很大的问题:如何将两个表关联起来

解决办法

添加一个部门编号字段在员工表里

id name gender dep_id
1 jason male 1
2 kevin male 2
3 tony male 2

外键字段的创建(foreign key)

外键字段专门用于记录表与表之间的数据关系,而数据关系有四种:一对多关系、多对多关系、一对一关系、没有关系

表关系之一对多

表数据关系的判定

关于表数据关系的判定一般采用换位思考的方法

针对员工表和部门表判断数据关系
1.先站在员工的角度:
	问:一条员工数据能否对应多条部门数据(一名员工能否属于多个部门)
	答:不可以
2.站在部门表的角度:
	问:一条部门的数据能否对应多条员工数据(一个部门能否有多名员工)
	答:可以
3.得出结论:员工表和部门表是“一对多” ,部门是一 员工是多
ps:针对"一对多"的关系,外键字段建在多的一方

实战

在有外键字段的时候,先写普通字段,再写外键字段

create table emp(id int primary key auto_increment,
                 name varchar(32),
                gender varchar(32) default 'male',
                 dep_id int,
                foreign key(dep_id) references dep(id));
create table dep(id int primary key auto_increment,
                dep_name varchar(32),
                dep_desc varchar(32));

mysql> insert into dep(dep_name,dep_desc) values('讲师部门','传授知识'),('财务部门','管理财务');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into emp(name,dep_id) values('jason',1),('kevin',2),('tony',2);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from dep;
+----+--------------+--------------+
| id | dep_name     | dep_desc     |
+----+--------------+--------------+
|  1 | 讲师部门     | 传授知识     |
|  2 | 财务部门     | 管理财务     |
+----+--------------+--------------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+-------+--------+--------+
| id | name  | gender | dep_id |
+----+-------+--------+--------+
|  1 | jason | male   |      1 |
|  2 | kevin | male   |      2 |
|  3 | tony  | male   |      2 |
+----+-------+--------+--------+
3 rows in set (0.00 sec)

注意

1.创建表的时候需要先创建被关联的表(没有外键),然后再创建关联表(有外键)
2.插入表数据的时候 针对外键字段只能填写被关联表字段已经穿线过的数据值
3.被关联的字段无法修改和删除(操作限制性太强)

级联更新,级联删除

级联更新,级联删除的作用是被关联的数据一旦变动,关联的数据同步变动

create table emp1(id int primary key auto_increment,
                 name varchar(32),
                 gender varchar(32) default 'male',
                 dep_id int,
                 foreign key(dep_id) references dep1(id)
                 on update cascade
                 on delete cascade);
                 
create table dep1(id int primary key auto_increment,
                 dep_name varchar(32),
                 dep_desc varchar(32));

insert into dep1(dep_name,dep_desc) values('讲师部门','传授知识'),('财务部门','管理财务');
insert into emp1(name,dep_id) values('jason',1),('kevin',2),('tony',2); 

mysql> update dep1 set id =10 where id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from dep1;
+----+--------------+--------------+
| id | dep_name     | dep_desc     |
+----+--------------+--------------+
|  1 | 讲师部门     | 传授知识     |
| 10 | 财务部门     | 管理财务     |
+----+--------------+--------------+
2 rows in set (0.00 sec)

mysql> select * from emp1;
+----+-------+--------+--------+
| id | name  | gender | dep_id |
+----+-------+--------+--------+
|  1 | jason | male   |      1 |
|  2 | kevin | male   |     10 |
|  3 | tony  | male   |     10 |
+----+-------+--------+--------+
3 rows in set (0.00 sec)



mysql> delete from dep1 where id =1;
Query OK, 1 row affected (0.01 sec)

mysql> select * from dep1;
+----+--------------+--------------+
| id | dep_name     | dep_desc     |
+----+--------------+--------------+
| 10 | 财务部门     | 管理财务     |
+----+--------------+--------------+

mysql> select * from emp1;
+----+-------+--------+--------+
| id | name  | gender | dep_id |
+----+-------+--------+--------+
|  2 | kevin | male   |     10 |
|  3 | tony  | male   |     10 |
+----+-------+--------+--------+

扩展

在实际工作中,很多时候可能并不会使用外键,因为外键增加了表之间的耦合度,不便于单独操作,资源消耗增加;我们为了能够描述出表数据的关系,又不想使用外键,可以通过自己写SQL,建立代码层面的关系

表关系之多对多

表数据关系的判定

以书籍表和作者表为例
1.站在书籍表的角度:
	问:一条书籍数据能否对应多条作者数据(一本书是否可有多个作者)
	答:可以
2.站在作者表的角度:
	问:一条作者数据能否应对多条书籍书籍(一个作者能否写多本书)
	答:可以
3.得出结论:表数据的关系是“多对多”的关系
ps:针对多对多的表关系,外键不能建在任意一方,需要单独开设第三张表,来存储数据关系

实战

create table book(id int primary key auto_increment,
                 title varchar(32)
                 );
create table author(id int primary key auto_increment,
                   name varchar(32)
                   );
create table book_author(id int primary key auto_increment,
                        book_id int,
                        foreign key(book_id) references book(id)
                        on update cascade
                        on delete cascade,
                        author_id int,
                        foreign key(author_id) references author(id)
                        on update cascade
                        on delete cascade);
                        
mysql> insert into book(title) values('python'),('java'),('go');
mysql> insert into author(name) values('jason'),('kevin');
mysql> insert into book_author(book_id,author_id) values(1,1),(1,2),(2,1),(3,1),(3,2);

mysql> select * from book_author;
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
|  1 |       1 |         1 |
|  2 |       1 |         2 |
|  3 |       2 |         1 |
|  4 |       3 |         1 |
|  5 |       3 |         2 |
+----+---------+-----------+

表关系之一对一

表数据关系的判定

以用户表和用户详情表为例
1.先站在用户表的角度
	问:一条用户用户数据能否对应多条用户详细数据(一个用户是否可以访问多个用户详细信息)
	答:不可以
2.站在用户详情表的角度
	问:一条用户详情的数据是否对应多条用户数据(以个用户详细数据是否能被多个用户使用)
	答:不可以
3.总结:两边都不可以,先考虑是不是他们之间没有关系;如果有关系就是“一对一”
ps:针对"一对一"的表关系,外键字段建在任何一张表都可以,但是建议建在查询率较高的表中便于后续查询

实战

create table user(id int primary key auto_increment,
                 name varchar(32),
                 detail_id int,
                 foreign key(detail_id) references user_detail(id)
                 on update cascade
                 on delete cascade);
                 
create table user_detail(id int primary key auto_increment,
                        addr varchar(32));
mysql> insert into user_detail(addr) values('北京'),('四川'),('上海'); 
mysql> insert into user(name,detail_id) values('nana',1),('jason',2),('aa',3);


mysql> select * from user;
+----+-------+-----------+
| id | name  | detail_id |
+----+-------+-----------+
|  1 | nana  |         1 |
|  2 | jason |         2 |
|  3 | aa    |         3 |
+----+-------+-----------+
3 rows in set (0.00 sec)

mysql> select * from user_detail;
+----+--------+
| id | addr   |
+----+--------+
|  1 | 北京   |
|  2 | 四川   |
|  3 | 上海   |
+----+--------+

作业

判断下列表数据关系 并自定义创建出表(ps:有些表数据关系不是确定 根据具体业务可能有变化)

服务器表与应用程序表

多对多的关系

create table server1(id int primary key auto_increment,
                   name varchar(32)
                   );
create table app(id int primary key auto_increment,
                  name varchar(32));
create table server1_app(id  int primary key auto_increment,
                         server1_id int,
                         foreign key(server1_id) references server1(id)
                         on update cascade
                         on delete cascade,
                         app_id int,
                         foreign key(app_id) references app(id)
                         on update cascade
                         on delete cascade);                  

课程表与班级表

首先:一门课程,可以被多个班级上;一个班级可以上多门课程;所以课程表与班级表示多对多的关系

create table course(id int primary key auto_increment,
                   name varchar(32)
                   );
create table class(id int primary key auto_increment,
                  name varchar(32),
                  num int);
create table course_class(id  int primary key auto_increment,
                         course_id int,
                         foreign key(course_id) references course(id)
                         on update cascade
                         on delete cascade,
                         class_id int,
                         foreign key(class_id) references class(id)
                         on update cascade
                         on delete cascade);
 
 mysql> insert into course(name) values('python'),('java'),('go');
 mysql> insert into class(name,num) values('金牌一班',45),('金牌二班',50);
 mysql> insert into course_class(course_id,class_id) values(1,1),(1,2),(2,1),(3,2);

学生表与班级表

首先:一个学生属于一个班级,一个班级含有多名学生;所以学生表与班级表示一对多关系

create table student(id int primary key auto_increment,
                    name varchar(32),
                    gender enum('male','female'),
                    age int,
                    class1_id int,
                    foreign key(class1_id) references class1(id)
                    on update cascade
                    on delete cascade);
create table class1(id int primary key auto_increment,
                   name varchar(32),
                   num int);
                   
mysql>  insert into class1(name,num) values('金牌一班',45),('金牌二班',50);
mysql> insert into student(name,gender,age,class1_id) values('nana','female',18,1),('kevin','male',19,2),('tony','male',19,1);

mysql> select * from student;
+----+-------+--------+------+-----------+
| id | name  | gender | age  | class1_id |
+----+-------+--------+------+-----------+
|  1 | nana  | female |   18 |         1 |
|  2 | kevin | male   |   19 |         2 |
|  3 | tony  | male   |   19 |         1 |
+----+-------+--------+------+-----------+

老师表与课程表

首先:一个老师可以教授多门课程,一门课程也可以被多个老师教授,所以老师表与课程表是多对多的关系

create table teacher(id int primary key auto_increment,
                    name varchar(32));
create table course1(id int primary key auto_increment,
                    name varchar(32));
create table teacher_course(id int primary key auto_increment,
                           teacher_id int,
                           foreign key(teacher_id) references teacher(id)
                           on update cascade
                           on delete cascade,
                            course1_id int,
                            foreign key(course1_id) references course1(id));

mysql> insert into teacher(name) values('jason'),('tony'),('oscar');
mysql> insert into course1(name) values('python'),('java'),('go');                          

书籍表与出版社表

首先:一本书籍只属于一个出版社,一个出版社可以出多本书;所以书籍表与出版社表是一对多的关系

create table book1(id int primary key auto_increment,
                 name varchar(32),
                 press_id int,
                 foreign key(press_id) references press(id)
                 on update cascade
                 on delete cascade);
create table press(id int primary key auto_increment,
                  name varchar(32));
                  
mysql> insert into press(name) values('北大'),('人民'),('浙大');  
mysql> insert into book1(name,press_id) values('python',1),('java',2),('go',1);

mysql> select * from book1;
+----+--------+----------+
| id | name   | press_id |
+----+--------+----------+
|  1 | python |        1 |
|  2 | java   |        2 |
|  3 | go     |        1 |
+----+--------+----------+

标签:约束条件,name,int,外键,id,dep,key,mysql,主键
From: https://www.cnblogs.com/luonacx/p/16592816.html

相关文章