一.多表关系介绍
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也会存在着各种联系,分为如下3类:
- 一对一
- 一对多或者多对一
- 多对多
一对一:
- 用户与用户详情的关系
- 常见于单表的拆分,以提高工作效率——将一张表中一部分的信息放在一张表中,其他详细的信息则放在另一张表中
- 在任意一方加入外键关联另一方的主键,并且为外键设置唯一约束unique~
一对多:
- 一个员工只能在一个部门,但一个部门可以有多个员工
- 实现:在多的一方建立外键,指向一的一方的主键
多对多:
- 一个学生可以学多门课,每门课也可以被多个 学生学
- 实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
- DataGrip有不错的可视化功能(下图)
二.概述
最基础的多表查询写法:
select * from student,class;
查询的多张表只需要用逗号分别隔开,但是此时查出来的数据并无什么实际意义:假设有50个学生,6个课程,则会查出来50*6=300条记录——相当于互相匹配,也就是学生会学全部的课,而每一门课都会被所有的学生学。该情况称为笛卡尔积。
笛卡尔积是指:数学中的集合A和集合B所有的组合情况。在多表查询中,需要消除无效的笛卡尔积。
将上述的SQL语句改为:
select * from student,class where student.dept_id=class.id;
其中id是class表的主键,dept_id为student关联class主键的外键。
多表查询的分类:
1.连接查询
- 内连接:查询A、B两表交集部分的数据
- 外连接:左外查询左表和交集,右外查询右表和交集
- 自连接:只有一张表,与自身进行连接查询(必须使用表别名)
2.子查询
三.内连接
1.隐式内连接
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.显式内连接
select e.name,d.name from emp e inner join dept d on e.dept_id=d.id;
- inner可以直接省略
- on后面加的是去除笛卡尔积的条件
四.外连接
1.左外连接
select 字段列表 from 表1 left [outer] join 表2 on 条件...;
2.右外连接
select 字段列表 from 表1 right [outer] join 表2 on 条件;
(实际开发中左外连接用的更多,在不改变业务需求的情况下直接将两表对调顺序即可~)
(要求查询结果完全包含哪个,就将其作为查询偏向的一侧)
五.自连接
select 字段列表 from 表A 别名A join 表A 别名B on 条件...;
(在用到自连接的场合里,往往需要将目标的一张表拆分为逻辑上的两张表~)
六.联合查询union
把多次查询的结果合并起来,形成一个新的查询结果集。
select 字段列表 from 表A……
union [all]
select 字段列表 from 表B……
- 如果将union all 改成 union ,则会去除重复的字段~
- 需要注意的是,只有查询字段一致时才能使用联合查询
七.子查询
SQL语句中嵌套select语句,就叫做子查询,又称为嵌套查询~
select * from t1 where column = (select column 1 from t2);
外部的sql语句,可以是insert、update、delete、select中的任何一个~
根据查询结果的不同,将子查询分为:
- 标量子查询:查询结果为单个值
- 列子查询:子查询结果为一列
- 行子查询:子查询结果我一行
- 表子查询:子查询结果为多行多列
根据子查询的位置:又可以分为where、from、select之后的子查询~
八.标量子查询
返回的结果是单个值,最简单的形式~
本质上是两步的查询过程一次性合并为一步~
当某种需要的条件暂时没有显式表出时,可以采用标量子查询将该条件作为标量查询出来,然后再将该标量作为目标条件再次查询~
select * from emp where dept_id = (select id from dept where name='软件工程');
九.列子查询
列子查询返回的结果是一列,即结果可以有很多行~
常见的操作符有:in、not in、any、some、all~
同理,比如此处查询计算机科学与技术和软件工程的全部学生的信息:
select * from emp where depi_id in(select id from dept where name='计科'
or name='软工');
再比如,选出所有考研数学一成绩比所有计科和软工学生都要高的人的信息:
select * from student where num>all(select num from student where depi_id in
(select id from dept where name='计科'or name='软工'));
容易犯低级错误的地方是:子查询的SQL语句不需要加额外的分号!
十.行子查询
结果会返回一行,即可以是多列共存~
如下:查询出所有俱乐部和国籍均与穆勒相同的球员信息~
select * from emp where (country,club)=(select country,club from player where
name='托马斯穆勒');
十一.表子查询
常用于from之后——将表子查询的结果作为一张新的临时表,再度进行查询~常用的操作符为in~
道理相同,不再赘述~要注意的是:由于结果有多个,所以常用in而不能用等于号~