MYSQL —— 约束和多表查询
一、前言
本文创作于学习MyBatis时发现MySql的约束和多表查询没有学习,为了使用MyBatis的多表配置,于是回头进行补充学习,本文使用的是IDEA专业版自带的数据库(DataGrip)。
二、约束
这里将给出一个表来演示数据库的约束类型和效果:
首先创建一个user表(下面演示时使用的是使用的DataGrip创建的user1(create_by_ui))当然,效果都是一样的:
create table user
(id int primary key auto_increment comment '主键',name varchar(10) not null unique comment '名字',age int check ( age > 0 && user.age <= 120 ) comment '年龄',status char(1) default '1' comment '状态',gender char(1) comment '性别'
) comment '用户表';
创建后我们向表中添加如下数据进行演示:
insert into user (name, age, status, gender)
values ('Tom1', 19, '1', '男'),('Tom2', 25, '0', '男');
insert into user (name, age, status, gender)
values ('Tom3', 19, '1', '男');
1.主键
我们通常将id设置为主键,并且通常让id自增,主键具有唯一性,是每行数据的标志,所以在一张表中主键都一定是不同的,否则事务的提交将会被取消,同时将会报错。
id int primary key auto_increment comment '主键',
2.唯一键
name varchar(10) not null unique comment '名字',
我们这里将name字段设置成了唯一键,并且要求其非空。
首先验证唯一性:
-- 验证唯一
insert into `user1(create_by_ui)` (name, age, status, gender)
values ('Tom3', 19, '1', '男');
这里我们再验证一下非空性:
-- 验证非空
insert into `user1(create_by_ui)` (name, age, status, gender)
values (null, 19, '1', '男');
执行后将会报错:
3.检查
age int check ( age > 0 && user.age <= 120 ) comment '年龄',
我们将age字段的数值大小限制到了0~120之间,这个需要通过check来实现(check的括号中就是约束条件)。
这里我们尝试插入如下数据,看看是否可以成功插入:
-- 验证check
insert into `user1(create_by_ui)` (name, age, status, gender)
values ('Tom3', 128, '1', '男');
显然是不行的:
4.默认
我们将status设置成了默认的‘1’,如果在插入新记录时没有为该字段赋值,系统会自动为该字段赋值为默认值。
insert into `user` (name, age, gender)
values ('Tom6', 26, '男');
可以看到,这里我们并没有设置插入的状态码,数据库直接将其赋值为了‘1’:
5.外键
一个表的外键可以连接另一个表的主键,所以在查询时,可以通过外键来检查该行数据和另一张表的对应主键数据的从属关系或者关联关系,为后续多表查询提供了前提条件。
首先创建两个表,并插入数据如下:
create table dept
(id int auto_increment comment 'ID' primary key,name varchar(50) not null comment '部门名称'
) comment '部门表';
INSERT INTO dept (id, name)
VALUES (1, '研发部'),(2, '市场部'),(3, '财务部'),(4, '销售部'),(5, '总经办');create table emp
(id int auto_increment comment 'ID' primary key,name varchar(50) not null comment '姓名',age int comment '年龄',job varchar(20) comment '职位',salary int comment '薪资',entrydate date comment '入职时间',managerid int comment '直属领导ID',dept_id int comment '部门ID'
) comment '员工表';INSERT INTO emp (id, name, age, job, salary, entrydate, managerid, dept_id)
VALUES (1, '金庸', 66, '总裁', 20000, '2000-01-01', null, 5),(2, '张无忌', 20, '项目经理', 12500, '2005-12-05', 1, 1),(3, '杨逍', 33, '开发', 8400, '2000-11-03', 2, 1),(4, '韦一笑', 48, '开发', 11000, '2002-02-05', 2, 1),(5, '常遇春', 43, '开发', 10500, '2004-09-07', 3, 1),(6, '小昭', 19, '程序员鼓励师', 6600, '2004-10-12', 2, 1);
创建好后,两个表如下:
下面的操作可以自行尝试,因为在界面化数据库可以通过更简单的方式选择,所以不做过多赘述。
添加外键:
-- 添加外键
alter table empadd constraint fk_emp_dept_id foreign key (dept_id) references dept (id);
删除外键:
-- 删除外键
alter table empdrop foreign key fk_emp_dept_id;
外键的更新行为,描述和演示如下:
-- 外键的删除和更新行为
-- cascade 更改父表主键,子表中的记录也会相应更改 删除父表中主键,子表相应记录直接删除
alter table empadd constraint fk_emp_dept_id foreign key (dept_id) references dept (id) on UPDATE cascade on DELETE cascade;-- set null 更改父表主键,子表中的记录也会相应更改 删除父表中主键,子表相应外键更新为null
alter table empadd constraint fk_emp_dept_id foreign key (dept_id) references dept (id) on UPDATE set null on DELETE set null;
三、多表查询
1.模型
(1)多对多
多对多查询需要通过一个中间表来实现,逻辑关系大概是这样的:
这里的中间表就是student_course表。
首先创建三个表,并插入数据:
create table student
(id int auto_increment primary key comment '主键ID',name varchar(10) comment '姓名',no varchar(10) comment '学号'
) comment '学生表';
insert into student
values (null, '黛绮丝', '2000100101'),(null, '谢逊', '2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104');create table course
(id int auto_increment primary key comment '主键ID',name varchar(10) comment '课程名称'
) comment '课程表';
insert into course
values (null, 'Java'),(null, 'PHP'),(null, 'MySQL'),(null, 'Hadoop');create table student_course
(id int auto_increment comment '主键' primary key,studentid int comment '学生ID',courseid int comment '课程ID',constraint fk_student foreign key (studentid) references student (id),constraint fk_course foreign key (courseid) references course (id)
) comment '学生课程中间表';
insert into student_course
values (null, 1, 1),(null, 1, 2),(null, 1, 3),(null, 2, 2),(null, 2, 3),(null, 3, 4);
创建好后如下:
(2)一对一
创建两个表如下,并插入数据:
create table tb_user
(id int auto_increment primary key comment '主键ID',name varchar(10) comment '姓名',age int comment '年龄',gender char(1) comment '1: 男,2: 女',phone char(11) comment '手机号'
) comment '用户基本信息表';create table tb_user_edu
(id int auto_increment primary key comment '主键ID',degree varchar(20) comment '学历',major varchar(50) comment '专业',primaryschool varchar(50) comment '小学',middleschool varchar(50) comment '中学',university varchar(50) comment '大学',userid int unique comment '用户ID',constraint fk_userid foreign key (userid) references tb_user (id)
) comment '用户教育信息表';insert into tb_user(id, name, age, gender, phone)
values (null, '黄渤', 45, '1', '18800001111'),(null, '冰冰', 35, '2', '18800002222'),(null, '码云', 55, '1', '18800008888'),(null, '李彦宏', 50, '1', '18800009999');insert into tb_user_edu(id, degree, major, primaryschool, middleschool, university, userid)
values (null, '本科', '舞蹈', '静安区第一小学', '静安区第一中学', '北京舞蹈学院', 1),(null, '硕士', '表演', '朝阳区第一小学', '朝阳区第一中学', '北京电影学院', 2),(null, '本科', '英语', '杭州市第一小学', '杭州市第一中学', '杭州师范大学', 3),(null, '本科', '应用数学', '阳泉第一小学', '阳泉区第一中学', '清华大学', 4);
2.查询
(1)内连接
内连接用于返回两个表中匹配的记录。只有在两个表中都存在匹配的记录时,才会返回结果。如果某一表中没有匹配的记录,则该记录不会出现在结果集中。
-- 多表查询 -- 笛卡尔积
select * from emp,dept where emp.dept_id = dept.id;
查询结果如下:
代入情景1:查询每一个员工的姓名,及关联的部门的名称
-- 1.查询每一个员工的姓名,及关联的部门的名称
-- 表结构:emp,dept
-- 连接条件:emp.dept_id = dept.id
select emp.name ,dept.name from emp,dept where emp.dept_id = dept.id;
当然也可以取别名:
-- 取别名(效果同上)
select e.name,d.name from emp e , dept d where e.dept_id= d.id;
代入情景2:查询每一个员工的姓名,及关联的部门的名称(显示内连接实现)
-- 2.查询每一个员工的姓名,及关联的部门的名称(显示内连接实现)-- inner join...on...
-- 表结构:emp,dept
-- 连接条件:emp.dept_id = dept.id
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
(2)外连接
外连接用于返回两个表中匹配的记录以及未匹配的记录。外连接包括左外连接和右外连接。
代入情景1:查询emp表的所有数据,和对应的部门信息(左外连接)
-- 1.查询emp表的所有数据,和对应的部门信息(左外连接)
-- 表结构:emp,dept
-- 连接条件:emp.dept_id=dept.id
select e.*,d.name from emp e left outer join dept d on e.dept_id = d.id;
效果如下:
代入情景2:查询dept表的所有数据,和对应的员工信息(右外连接)
-- 2.查询dept表的所有数据,和对应的员工信息(右外连接)
select d.*,e.* from emp e right outer join dept d on e.dept_id = d.id;
查询结果如下:
(3)自连接
自连接是指一张表与自身进行连接的操作。在使用自连接的时候,可以把两个字段看成两个表进行外连接。
代入情景1:查询员工及其所属领导的名字
-- 1.查询员工及其所属领导的名字
-- 表结构emp()必须取别名
select a.name,b.name from emp a, emp b where a.managerid = b.id;
代入情景2:查询所有员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来
-- 2.查询所有员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来
-- 表结构:emp a,emp b
select a.name,b.name from emp a left join emp b on a.managerid = b.id;
查询效果如下: