Day05 MySQL的多表关系及概述,多表查询分类方式及练习代码

之前学习的都是单表查询,今天终于学习多表查询了!

多表关系: 

1.一对多

案例:部门表()和员工(所属部门)表()的关系

实现:在的一方建立外键,指向的一方的主键

2.多对多

案例:学生与课程的关系,每个学生可以选多个课程,每个课程可被多个学生选择

实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方的主键

更直观可视化:在菜单的中间表右键点击diagrams--show visualization

3.一对一

案例:用户和用户详情的关系

实现:单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表,在任意一方加入外键,关联另一方的主键,并且设置外键为唯一的(保证一条用户基本信息对应一条受教育经历)

代码练习:


#一对多,员工与部门
create table dept(
    id int auto_increment primary key comment 'ID唯一标识',
    name varchar(10) comment '部门名'
)comment '公司部门表';
insert into dept (id,name) values(1,'总经办'),(2,'市场部'),(3,'技术部'),(4,'销售部'),(5,'公关部'),(6,'财务部'),(7,'人事部');
#向表emp插入数据
insert into emp(id,age,name,entrydate,emp.managerid,dept_id) values(1,73,'员工a','2002-01-09',2,4),(2,23,'员工b','2002-01-29',1,4),(3,63,'员工c','2002-01-29',1,1),(4,44,'员工d','2022-01-29',3,4),(5,35,'员工e','2005-01-29',1,6),
                                                                   (6,31,'小强','2012-03-29',1,6),(7,23,'小明','2002-01-19',1,2),(8,76,'小化','2008-01-19',3,3),(9,22,'小亮','2006-01-19',1,4),(10,53,'小钟','2022-03-19',3,7);


#多对多,学生选课
  # 课程表
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,'Hadoop'),(null,'MySql');
  #学生表
create table student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    studentno  varchar(10) comment '学号'

)comment  '学生表';
insert into student values (null,'黛琪思','20010101'),(null,'谢逊','20010102'),(null,'殷天正','20010103'),(null,'韦一笑','20010104');
  #中间表
create table student_course(
    id int auto_increment primary key comment '主键ID',
    studentid int not null comment '学生ID',
    courseid int not null comment '课程ID',
    constraint fk_courseid foreign key (courseid) references  course(id),
    constraint  fk_studentid foreign key (studentid) references student(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);

#一对一
create table tb_user(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    age int comment '年龄'
)comment '用户基本信息表'
insert into tb_user (id,name,age) values (null,'黄渤',43),(null,'冰冰',18),(null,'马云',38);
create table tb_user_edu(
        id int auto_increment primary key comment '主键ID',
        degree varchar(10) comment '学历',
        primaryschool varchar(50) comment '小学',
        userid int unique  comment '用户id',
        constraint fk_userid foreign key (userid) references tb_user(id)

)comment '用户受教育经历';
insert into tb_user_edu(id,degree,primaryschool,userid) values (null,'本科','静安区第一中学',1),(null,'本科','杭州市第一中学',2),(null,'本科','朝阳区第一中学',3);


多表查询概述:

从多张表中查询数据

笛卡尔积:集合A和集合B的所有组合情况(在多表查询时,需消除无效的笛卡尔积)

图示:

多表查询分类

1.连接查询: 

   内连接:相当于查询A,B交集的数据

         >隐式内连接语法:select 字段列表 from 表1,表2 where 条件...;

         >显式内连接语法:select 字段列表 from 表1[inner] join 表2 on 连接条件..;

   外连接:包括左外连接和右外连接。左外连接查询左表的所有数据,以及左右两张表交集部分数据,右外连接查询右表的所有数据,以及左右两张表交集部分数据

         >左外连接语法:select 字段列表 from 表1 left [outer] join 表2 on 条件....;

         >右外连接语法:select 字段列表 from 表1 right [outer] join 表2 on 条件....;

   自连接:当前表与自身的连接查询,自连接必须使用表别名,自连接查询可以是内连接查询也可以是外连接查询

         >自连接语法:select 字段列表 from 表A 别名A join 表A 别名B on条件...;

代码练习


#例1:查询每个员工姓名,及其关联的部门名称
#隐式内连接
select emp.name,dept.name from dept,emp where emp.dept_id=dept.id;
select e.name,d.name from dept d,emp e where e.dept_id=d.id;
#显式内连接
select e.name,d.name from dept d join emp e on e.dept_id=d.id;

#例2.1:查询emp表的所有数据和对应部门信息(左外连接实现)
select emp.*,dept.name from emp left join dept on emp.dept_id=dept.id;
#例2.2:查询dept表的所有数据和对应员工信息(右外连接实现)
select e.*,d.* from emp e right join dept d on d.id = e.dept_id ;  #公关部没有对应员工

#例3.1查询员工及其所属领导的名字(自连接,用内连接查询)
select a.name "员工名字",b.name "领导" from emp a,emp b where a.managerid=b.id;  #员工小强没有领导因此不会被查询出来
#例3.2查询员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来(自连接,左外连接查询)
select a.name "员工",b.name "领导" from emp a left join emp b on a.managerid=b.id ; #就算员工小强没有领导也会被查询出来

2.子查询

SQL语句中嵌套select语句,称为嵌套查询,又称子查询

语法: select *from t1 where column1=(select column1 from t2);

子查询外部的语句可以是insert/update/delete/select中的任何一个

根据查询结果不同,分为:

         >标量子查询(查询结果为单个值)

         >列子查询(查询结果为一列,in/not in/all/some/any)

         >行子查询(查询结果为一行)

         >表子查询(查询结果为多行多列)

根据子查询位置,分为where之后,from之后,select之后(这还不太理解)

代码练习:


#标量子查询
#例4.1 查询”销售部“的所有员工信息  思路:查询销售部ID--根据ID 查员工信息
select *from emp where dept_id=(select id from dept where name='销售部');
#例4.2查询在员工a之后入职的员工信息
select *from emp where emp.entrydate>(select entrydate from emp where name='员工a');


#列子查询(查询结果为一列)
#例5.1查询销售部和市场部的所有员工信息
select *from emp where emp.dept_id in (select id from dept where name in('销售部','市场部'));
#例5.2查询比财务部所有人年龄都高的员工信息
#这道题不可以用聚合函数max,因为得到财务部人员的年龄返回的是一个列向量,而max()括号里需要的是字段名
select *from emp where age>all(select age from emp where dept_id=(select id from dept where name='财务部'));
#例5.3查询比市场部任意一人年龄大的员工信息
select *from emp where age>any(select age from emp where dept_id=(select id from dept where name='市场部'));

#行子查询(查询结果为一行)
#例6查询与”员工a“的  年龄及直属领导相同  的员工信息
select  *from  emp where(age,managerid)=(select age,managerid from emp where name='员工a');

#表子查询(返回结果为多行多列)常用操作符是in
#例7.1查询与员工a,员工b的年龄和领导相同的员工信息
select *from emp where (age,managerid)in (select  age ,managerid from emp where name in('员工a','员工b'));
#例7.2查询入职时间是”2006-01-01“之后的员工信息,及其部门信息
#select *from emp where emp.entrydate>'2006-01-01';
select emp.*,dept.name from (select *from emp where emp.entrydate>'2006-01-01') emp left join dept on emp.dept_id=dept.id;

3.联合查询(union、union all)

就是把多次查询的结果合并起来,形成一个新查询的结果集,对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。union all得到的数据可能有重复数据,而union会去除重复的数据。

语法:

select 字段列表 from 表A...

union [All]

select 字段列表 from 表B....

例:将入职时间大于2008年的员工和年龄大于50岁的员工全部查询出来

#联合查询 例:将入职时间大于2008年的员工和年龄大于50岁的员工全部查询出来
select *from emp where datediff(entrydate,'2008-01-01')>0
union all
select *from emp where age>50;

猜你喜欢

转载自blog.csdn.net/m0_67042480/article/details/128910389