05MySQL多表查询全解析
mysql的多表查询
概述:
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:
1:一对多(多对一)
2:多对多
3:一对一
多表查询-笛卡尔积
笛卡尔积:笛卡尔乘积是指在数学中,两个集合A集合和B集合的所有组合情况。(在多表查询时,需要消除无效的笛卡尔积)
-- 笛卡尔查询,不过滤无用信息
SELECT * FROM emp,dept;-- 内连接查询,可以过滤无用信息
SELECT * FROM emp,dept where emp.dept_id = dept.id order by emp.id asc;
多表查询-内连接查询
内连接查询的是两张表交集的部分
语法:
隐式内连接:
SELECT 字段列表 FROM 表1,表2 WHERE 条件…;
显示内连接:
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件…;
-- 隐式内连接
SELECT e.name,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 显示内连接
SELECT e.name,d.name
FROM emp e
INNER JOIN dept d
ON e.dept_id=d.id;
在实际开发中,推荐使用显式内连接的写法,尤其是在多表连接时,INNER JOIN
的语法能更清晰地体现表之间的关系,使代码更易读、易维护。
多表查询-外连接查询
语法:
左外连接查询
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件...;
返回表1的所有记录,以及表2与表1满足连接条件的记录
右外连接查询
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件...;
返回表2的所有记录,以及表1与表2满足连接条件的记录
左右外连接常用于需要完整保留主表数据并关联从表信息的场景
-- 外连接演示
-- 查询emp表的所有数据,和对应的部门信息(左外连接)
SELECT e.*,d.name AS d_name
FROM emp e
LEFT OUTER JOIN dept d
ON e.dept_id=d.id;-- 查询dept表的所有数据,和对应的员工信息(右外连接)
SELECT d.*,e.*
FROM emp e
RIGHT OUTER JOIN dept d
ON e.dept_id=d.id;
多表查询-自连接查询
自连接查询是 SQL 中一种特殊的多表查询方式,它指的是同一张表与自身进行连接,通常用于处理表中存在层级关系或自引用关系的数据。
例如,在员工表中,可能有一个 manager_id 字段指向该员工的上级领导(也是员工表中的一条记录),这时就可以通过自连接查询员工与其上级的信息。
自连接查询,可以是内连接查询,也可以是外连接查询。
自连接的内连接查询:
SELECT 字段列表 FROM 表A 别名a,表A 别名b WHERE 条件语句;
自连接的外连接查询:
SELECT 字段列表 FROM 表A 别名a [左/右] JOIN 表A 别名b ON 条件语句;
-- 1. 查询员工 及其 所属领导的名字
SELECT a.name '员工',b.name '上司' FROM emp a,emp b WHERE a.managerid=b.id; -- 2. 查询所有员工 emp 及其领导的名字 emp,如果员工没有领导,也需要查询出来
SELECT a.name '员工',b.name '上司' FROM emp a left join emp b ON a.managerid=b.id;
多表查询-联合查询
对于 union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
联合查询语法:
SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...;如果添加all参数,则会显示重复的记录,不添加就是去重
-- 1.将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来。
SELECT * FROM emp WHERE age >50
union
SELECT * FROM emp WHERE salary < 5000;
多表查询-子查询
子查询:
概念:SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。
SELECT * FROM t1 WHERE column1=(SELECT column1 FROM t2);
子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个。
根据子查询结果不同,分为:
1标量子查询(子查询结果为单个值)
2列子查询(子查询结果为一列)
3行子查询(子查询结果为一行)
4表子查询(子查询结果为多行多列)
根据子查询位置,分为:WHERE之后、FROM之后、SELECT之后。
标量子查询
子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询成为标量子查询。 常用的操作符: = <> > >= < <=
-- 标量子查询-- 1.查询“销售部”的所有员工信息
-- a.查询“销售部”部门ID
-- b.根据销售部部门ID,查询员工信息
SELECT *
FROM emp
WHERE dept_id=(SELECT id FROM dept WHERE name='销售部');-- 2.查询在“方东白”入职之后的员工信息
-- a.查询方东白的入职日期
-- b.查询指定入职日期之后入职的员工信息
SELECT *
FROM emp
WHERE entrydate >= (SELECT entrydate FROM emp WHERE name='方东白');
列子查询
子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。
常用的操作符:IN、NOT IN、ANY、SOME、ALL
IN | 判断字段是否在这些值中,如果符合则返回 |
NOT IN | 与IN相反 |
ANY | 满足任意一个则返回 |
SOME | 完全等于any |
ALL | 必须所有值都满足才返回 |
-- 列子查询
-- 1.查询“销售部”和“市场部”的所有员工信息
-- a.查询“销售部”和“市场部”的部门ID
SELECT id FROM dept WHERE name = '销售部' OR name = '市场部';
-- b.根据部门ID,查询员工信息
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE name = '销售部' OR name = '市场部');
SELECT * FROM emp WHERE dept_id NOt IN (2,4,6);
-- 2.查询比财务部所有人工资都高的员工信息
-- a.查询所有财务部人员工资
SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '财务部');
-- b.比财务部所有人工资都高的员工信息
SELECT * FROM emp WHERE salary > ALL (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '财务部'));-- 3.查询比研发部其中任意一人工资高的员工信息
-- a.查询研发部所有人工资
SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部');
-- b.比研发部其中任意一人工资高的员工信息
SELECT * FROM emp WHERE salary > ANY (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部'));
SELECT * FROM emp WHERE salary > SO(SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部'));
行子查询
子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
常用的操作符:=、<>、IN、NOT IN
-- 行子查询
-- 1.查询与“张无忌”的薪资及直属领导相同的员工信息;
-- a.查询“张无忌”的薪资及直属领导
SELECT salary,managerid FROM emp WHERE name ='张无忌';
-- b.查询与“张无忌”的薪资及直属领导相同的员工信息;
SELECT * FROM emp WHERE (salary,managerid) = (12500,1);
SELECT * FROM emp WHERE (salary,managerid) = (SELECT salary,managerid FROM emp WHERE name ='张无忌');
表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询。
可以这样简单理解,但更准确地说,表子查询(Table Subquery)是指子查询返回的结果是一个多行多列的数据集(类似一张 “临时表”),主查询会基于这个 “临时表” 来进行进一步的查询操作(比如关联查询、IN
匹配等)。
-- 表子查询-- 1.查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
-- a.查询“鹿杖客”,“宋远桥”的职位和薪资
SELECT salary,job FROM emp WHERE name= '鹿杖客' OR name= '宋远桥';
-- b.查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
SELECT * FROM emp WHERE (salary,job) IN (SELECT salary,job FROM emp WHERE name= '鹿杖客' OR name= '宋远桥');-- 2.查询入职日期是"2006-01-01"之后的员工信息,及其部门信息
-- a.入职日期是"2006-01-01"之后的员工信息
SELECT * FROM emp WHERE entrydate > '2006-01-01';
-- b.查询这部分员工,对应的部门信息;
SELECT e.*,d.* FROM (SELECT * FROM emp WHERE entrydate > '2006-01-01') e left join dept d ON e.dept_id=d.id;
多表查询--综合练习
-- 1.查询员工的姓名、年龄、职位、部门信息(隐式内连接)
SELECT e.name,e.age,e.job,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 2.查询年龄小于30岁的员工的姓名、年龄、职位、部门信息(显式内连接)
SELECT e.name,e.age,e.job,d.name
FROM emp e
INNER JOIN dept d
ON e.dept_id=d.id
WHERE e.age < 30;-- 3.查询拥有员工的部门ID、部门名称
SELECT DISTINCT d.id,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 4.查询所有年龄大于40岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来
SELECT e.*,d.name
FROM emp e
LEFT OUTER JOIN dept d
ON e.dept_id=d.id
WHERE e.age > 40;-- 5.查询所有员工的工资等级
SELECT e.*,s.grade
FROM emp e,salgrade s
WHERE e.salary BETWEEN s.losal AND s.hisal;-- 6.查询“研发部”所有员工的信息及工资等级
SELECT e.*,d.name,s.grade
FROM emp e,dept d, salgrade s
WHERE e.dept_id=d.id
AND d.name = '研发部'
AND e.salary BETWEEN s.losal AND s.hisal;-- 7.查询“研发部”员工的平均工资
SELECT avg(e.salary)
FROM emp e,dept d
WHERE d.name= '研发部' AND e.dept_id=d.id-- 8.查询工资比“灭绝”高的员工信息。
SELECT e.*
FROM emp e
WHERE salary > (SELECT salary FROM emp e WHERE name='灭绝')-- 9.查询比平均薪资高的员工信息
SELECT *
FROM emp
WHERE salary > (SELECT avg(salary) FROM emp );-- 10.查询低于本部门平均工资的员工信息
SELECT e2.* FROM emp e2
WHERE salary < (SELECT avg(salary) FROM emp e1 WHERE e1.dept_id=e2.dept_id);-- 11.查询所有的部门信息,并统计部门的员工人数
SELECT d.id,d.name,(SELECT count(*) FROM emp e WHERE e.dept_id=d.id) FROM dept d;
这是我的个人学习笔记,主要用于记录自己对知识点的理解和梳理。由于目前仍在学习探索阶段,内容中难免存在理解偏差或表述疏漏,恳请各位大佬不吝赐教,多提宝贵意见~ 若有不同看法,欢迎理性交流探讨,感谢包容与指正!