当前位置: 首页 > article >正文

数据库-多表查询

介绍(什么是多表查询?)

多表查询:查询时从多张表中获取所需数据

单表查询的SQL语句:select 字段列表 from 表名;

那么要执行多表查询,只需要使用逗号分隔多张表即可

如: select 字段列表 from 表1, 表2;

多表查询可能的结果--笛卡尔积 

 查询用户表和部门表中的数据:

select * from  emp , dept;

 

此时,我们看到查询结果中包含了大量的结果集,总共180条记录,而这其实就是员工表所有的记录(30行)与部门表所有记录(6行)的所有组合情况,这种现象称之为笛卡尔积

笛卡尔积:笛卡尔乘积是指在数学中,两个集合(A集合和B集合)的所有组合情况。

在多表查询时,需要消除无效的笛卡尔积,只保留表关联部分的数据。

 

在SQL语句中,如何去除无效的笛卡尔积呢?

只需要给多表查询加上连接查询的条件即可。 

select * from emp , dept where emp.dept_id = dept.id ;

这样,我们就查询出来了所有的员工,及其这个员工所属的部门信息。 而由于id为29、30的员工,没有dept_id字段值,所以在多表查询时,根据连接查询的条件并没有查询到。

分类

多表查询可以分为:

  1. 连接查询

    1. 连接:相当于查询A、B交集部分数据

    2. 连接

      • 连接:查询左表所有数据(包括两张表交集部分数据)

      • 连接:查询右表所有数据(包括两张表交集部分数据)

  2. 子查询

内连接

内连接查询:查询两表或多表中交集部分数据。

内连接从语法上可以分为:

  • 隐式内连接

  • 显式内连接

隐式内连接语法:
select  字段列表   from   表1 , 表2   where  条件 ... ;
显式内连接语法:
select  字段列表   from   表1  [ inner ]  join 表2  on  连接条件 ... ;
 案例
  • 案例1:查询所有员工的ID,姓名,及所属的部门名称

    • 隐式内连接实现

select emp.id, emp.name, dept.name from emp , dept where emp.dept_id = dept.id;
  • 显式内连接实现

select emp.id, emp.name, dept.name from emp inner join dept on emp.dept_id = dept.id;
  • 案例2:查询 性别为男, 且工资 高于8000 的员工的ID, 姓名, 及所属的部门名称

    • 隐式内连接实现

select emp.id, emp.name, dept.name from emp , dept where emp.dept_id = dept.id and emp.gender = 1 and emp.salary > 8000;

        显式内连接实现

select emp.id, emp.name, dept.name from emp inner join dept on emp.dept_id = dept.id where emp.gender = 1 and emp.salary > 8000;

在多表联查时,我们指定字段时,需要在字段名前面加上表名,来指定具体是哪一张的字段。 如:emp.dept_id 

如果不指定可能会报错。例如id这个字段在员工表和部门表都有,如果只单独指定id字段,

编译器无法判断你想查询的是哪一个表的id,这个时候数据库在查询时就会报错。

这个时候我们发现直接用原表名书写会非常麻烦,那有没有解决办法呢? 

给表起别名简化书写:

select  字段列表 from 表1 as 别名1 , 表2 as  别名2  where  条件 ... ;

select  字段列表 from 表1 别名1 , 表2  别名2  where  条件 ... ;  -- as 可以省略

使用了别名的多表查询:

select e.id, e.name, d.name from emp as e , dept as d where e.dept_id = d.id and e.gender = 1 and e.salary > 8000;
注意事项:

一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。 

外连接(可以查到null值,细节)

外连接分为两种:左外连接 和 右外连接。

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

左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。 

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

 右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。

案例

案例1:查询员工表 所有 员工的姓名, 和对应的部门名称 (左外连接)

-- 左外连接:以left join关键字左边的表为主表,查询主表中所有数据,以及和主表匹配的右边表中的数据
select e.name , d.name  from emp as e left join dept as d on e.dept_id = d.id ;

案例2:查询部门表 所有 部门的名称, 和对应的员工名称 (右外连接)

-- 右外连接:以right join关键字右边的表为主表,查询主表中所有数据,以及和主表匹配的左边表中的数据
select e.name , d.name from emp as e right join dept as d on e.dept_id = d.id;

案例3:查询工资 高于8000 的 所有员工的姓名, 和对应的部门名称 (左外连接)

select e.name , d.name  from emp as e left join dept as d on e.dept_id = d.id where e.salary > 8000;
注意事项:

左外连接和右外连接是可以相互替换的,只需要调整连接查询时SQL语句中表的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。

子查询

介绍

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

SELECT  *  FROM   t1   WHERE  column1 =  ( SELECT  column1  FROM  t2 ... );

 子查询外部的语句可以是insert / update / delete / select 的任何一个,最常见的是 select。

根据子查询结果的不同分为:

  1. 标量子查询(子查询结果为单个值 [一行一列])

  2. 列子查询(子查询结果为一列,但可以是多行

  3. 行子查询(子查询结果为一行,但可以是多列

  4. 表子查询(子查询结果为多行多列[相当于子查询结果是一张表]

子查询可以书写的位置:

  1. where之后

  2. from之后

  3. select之后

子查询的要点是,先对需求做拆分,明确具体的步骤,然后再逐条编写SQL语句。 最终将多条SQL语句合并为一条。(核心思路)

标量子查询

子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式这种子查询称为标量子查询

常用的操作符: = <> > >= < <=

  • 案例1:查询 最早入职 的员工信息

-- 1. 查询最早的入职时间
select min(entry_date) from emp;  -- 结果: 2000-01-01

-- 2. 查询入职时间 = 最早入职时间的员工信息
select * from emp where entry_date = '2000-01-01';

-- 3. 合并为一条SQL
select * from emp where entry_date = (select min(entry_date) from emp);
  • 案例2:查询在 阮小五 入职之后入职的员工信息

-- 1. 查询 "阮小五" 的入职日期
select entry_date from emp where name = '阮小五'; -- 结果: 2015-01-01

-- 2. 根据上述查询到的这个入职日期, 查询在该日期之后入职的员工信息
select * from emp where entry_date > '2015-01-01';

-- 3. 合并SQL为一条SQL
select * from emp where entry_date > (select entry_date from emp where name = '阮小五');
 列子查询

子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。

常用的操作符:

操作符描述
in(用的很多)在指定的集合范围之内,多选一
not in不在指定的集合范围之内
  • 案例1:查询 "教研部" 和 "咨询部" 的所有员工信息

-- 1. 查询 "教研部" 和 "咨询部" 的部门ID
select id from dept where name = '教研部' or name = '咨询部'; -- 结果: 3,2

-- 2. 根据上面查询出来的部门ID, 查询员工信息
select * from emp where dept_id in(3,2);

-- 3. 合并SQL为一条SQL语句
select * from emp where dept_id in (select id from dept where name = '教研部' or name = '咨询部');
行子查询

子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。

常用的操作符:= 、<> 、IN 、NOT IN

  • 案例1:查询与 "李忠" 的薪资 及 职位都相同的员工信息

-- 1. 查询 "李忠" 的薪资和职位
select salary , job from emp where name = '李忠'; -- 结果: 5000, 5

-- 2. 根据上述查询到的薪资和职位 , 查询对应员工的信息
select * from emp where (salary, job) = (5000,5);

-- 3. 将两条SQL合并为一条SQL
select * from emp where (salary, job) = (select salary , job from emp where name = '李忠');
 表子查询

子查询返回的结果是多行多列,常作为临时表,这种子查询称为表子查询。

  • 案例:获取每个部门中薪资最高的员工信息

-- a. 获取每个部门的最高薪资
select dept_id, max(salary) from emp group by dept_id;

-- b. 查询每个部门中薪资最高的员工信息
select * from emp e , (select dept_id, max(salary) max_sal from emp group by dept_id) a
    where e.dept_id = a.dept_id and e.salary = a.max_sal;

多表查询-加深理解案例

根据需求,完成多表查询的SQL语句的编写。

  • 1. 查询 "教研部" 性别为 男,且在 "2011-05-01" 之后入职的员工信息 。

select e.* from emp as e , dept as d where e.dept_id = d.id and d.name = '教研部' and e.gender = 1 and e.entry_date > '2011-05-01';
  • 2. 查询工资 低于公司平均工资的 且 性别为男 的员工信息 。

select e.* from emp as e , dept as d where e.dept_id = d.id and e.salary < (select avg(salary) from emp) and e.gender = 1;
  • 3. 查询部门人数超过 10 人的部门名称 。

select d.name , count(*) from emp as e , dept as d where e.dept_id = d.id group by d.name having count(*) > 10;
  • 4. 查询在 "2010-05-01" 后入职,且薪资高于 10000 的 "教研部" 员工信息,并根据薪资倒序排序。

select * from emp e , dept d where e.dept_id = d.id and e.entry_date > '2010-05-01' and e.salary > 10000 and d.name = '教研部' order by e.salary desc;
  • 5. 查询工资 低于本部门平均工资的员工信息 。【难】

-- 5.1 查询每个部门的平均工资
select dept_id, avg(salary) avg_sal from emp group by dept_id;

-- 5.2 查询工资 低于本部门平均工资 的员工信息 。
select e.* from emp e , (select dept_id, avg(salary) avg_sal from emp group by dept_id) as a
          where e.dept_id = a.dept_id and e.salary < a.avg_sal;

http://www.kler.cn/a/515107.html

相关文章:

  • 3.CSS的背景
  • 免费!无水印下载!
  • GDB相比IDE有什么优点
  • SpringCloud微服务Gateway网关简单集成Sentinel
  • 服务器日志自动上传到阿里云OSS备份
  • elementUI Table组件实现表头吸顶效果
  • git远程仓库如何修改
  • 简单排序算法
  • MATLAB绘图时线段颜色、数据点形状与颜色等设置,介绍
  • 手机版扫描王导出 PDF、快速文本识别工具扫描纸张
  • 9. 神经网络(一.神经元模型)
  • 5.SQLAlchemy对两张有关联关系表查询
  • IM系统设计
  • 4.JoranConfigurator解析logbak.xml
  • IDEA中将String类型转json格式
  • 学python的第四天:输入(重制版)
  • 如何使用Python脚本将本地项目上传到 GitHub
  • C语言练习(19)
  • 学习笔记——动态规划
  • Math Reference Notes: 反函数
  • 第一讲 方程组的几何解释——以列向量线性组合的角度看方程组
  • NIO | 什么是Java中的NIO —— 结合业务场景理解 NIO (一)
  • 【Day24 LeetCode】贪心Ⅱ
  • 数据分库分表和迁移方案
  • 利用ML.NET精准提取人名
  • PyQt5之QCalendarWidget