【MySQL】多表查询

文章目录

  • 多表查询是什么?
  • 一、笛卡尔积(或交叉连接)
  • 二、多表查询分类
    • 分类1:等值连接 vs 非等值连接
      • 等值连接
      • 非等值连接
    • 分类2:自连接 vs 非自连接
    • 分类2:内连接 vs 外连接
  • 三、SQL99
    • SQL99 实现 内连接
    • SQL99 实现 外连接(OUTER JOIN)
      • 左外连接(LEFT OUTER JOIN)
      • 右外连接(RIGHT OUTER JOIN)
      • 满外连接(FULL OUTER JOIN)
    • UNION 和 UNION ALL的使用
  • 四、7种SQL JOINS的实现
    • 1. 内连接
    • 2. 左外连接
    • 3. 右外连接
    • 4.左外连接 但查NULL(A - A∩B)
    • 5. 右外联接 但查Null(B - A∩B)
    • 6.满外连接 A∪B
    • 7. 满外连接 但是查的是Null -> (A - A∩B) ∪ (B - A∩B)
  • 五、SQL99 语法新特性
    • 自然连接 NATURAL
    • USING连接
  • 总结
  • 综合练习


多表查询是什么?

也称为关联查询,指两个或更多个表一起完成查询操作。

前提条件:
这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。
比如:员工表和部门表,这两个表依靠“部门编号”进行关联。

以下错误的实现方式:

#案例:查询员工的姓名及其部门名称
SELECT last_name, department_name
FROM employees, departments;

jieguo
总共查出:2889条数据
但是:
错误
107 * 27 == 2889 也就是 每个员工和每一个部门都匹配了 一次

以上为:笛卡尔积的错误


一、笛卡尔积(或交叉连接)

笛卡尔积也称为交叉连接,英文是 CROSS JOIN
作用就是可以把任意表进行连接,即使这两张表不相关。

针对以上错误案例的分析: 为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
语法变为:

SELECT	table1.column, table2.column
FROM	table1, table2
WHERE	table1.column1 = table2.column2;  #连接条件

正确案例:

SELECT last_name,department_name
FROM employees,departments
WHERE employees.department_id = departments.department_id;

XG

二、多表查询分类

主外

分类1:等值连接 vs 非等值连接

等值连接

1.列名加前缀
在表中有相同列时,在列名之前加上表名前缀(也就是把两张表的ID关联起来)
效果
如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。

SELECT employees.last_name,departments.department_name,departments.department_id
FROM employees,departments
WHERE employees.department_id = departments.department_id;

建议:从sql优化的角度,建议多表查询时,每个字段前都指明其所在的表。


2.表起别名
也可以给表起别名,如果给表起了别名,一旦在SELECT或WHERE中使用表名的话,则必须使用表的别名,而不能再使用表的原名。

SELECT e.last_name,d.department_name,d.department_id
FROM employees e,departments d
WHERE e.department_id = d.department_id;

3.连接多个表 用AND
如果有n个表实现多表的查询,则需要至少n-1个连接条件

#练习:查询员工的employee_id,last_name,department_name,city
SELECT e.last_name,d.department_name,l.city,e.department_id,l.location_id
FROM employees e,departments d,locations l
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id;

效果

非等值连接

上

#标出员工表中的员工工资 在工作等级表中对应的薪资等级
SELECT e.employee_id,e.last_name,e.salary,j.grade_level
FROM employees e,job_grades j 
where e.salary BETWEEN j.lowest_sal AND j.highest_sal;

效果

分类2:自连接 vs 非自连接

表
当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。
然后两个表再进行内连接,外连接等查询。
(同一张表,不同的查询条件)
描述
emp表的管理员ID 对应 员工ID 所以 使用mgr表中的员工与其关联!

# 员工表员工ID 与 员工表管理ID 是同一个 通过where 关联ID
-- CONCAT 合并函数 --
SELECT CONCAT(e.last_name,' work for ',m.last_name)
FROM employees e,employees m
WHERE e.manager_id = m.employee_id;

效果

SELECT emp.employee_id AS "员工ID",emp.last_name AS "员工名字",mgr.manager_id AS "管理ID",mgr.last_name AS "管理名字" 
FROM employees emp,employees mgr
WHERE emp.manager_id = mgr.employee_id;

修改

#练习:查询出last_name为 ‘Chen’ 的员工的 manager 的信息。
SELECT emp.employee_id,emp.last_name AS "员工名字",mgr.last_name  as "管理员名字"
FROM employees emp,employees mgr 
WHERE emp.manager_id = mgr.employee_id
AND emp.last_name like '%Chen%';

运行

分类2:内连接 vs 外连接

概念:

  • 内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
  • 外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

内连接: 查出条件匹配的全部数据,那么有不匹配的数据,就不会显示出来了
举例:

SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id; -- 查出106条数据 --

可是 员工数据 有107条,也就是说 还有一个人没有对应的部门(也就是没有匹配到数据)


如果我们需要显示这个不匹配的数据,就是用外连接,让不匹配的显示为空(Null)

外连接分为:
- 左外连接
- 右外连接
- 满外连接

SQL92 实现外连接:

  • 在 SQL92 中采用(+)代表从表所在的位置。即左或右外连接中,(+) 表示哪个是从表。

  • Oracle 对 SQL92 支持较好,而 MySQL 则不支持 SQL92 的外连接。

    #左外连接
    SELECT last_name,department_name
    FROM employees ,departments
    WHERE employees.department_id = departments.department_id(+);#右外连接
    SELECT last_name,department_name
    FROM employees ,departments
    WHERE employees.department_id(+) = departments.department_id;
    
  • 而且在 SQL92 中,只有左外连接和右外连接,没有满(或全)外连接。

三、SQL99

以上代码都使用的SQL92
SQL99使用 JOIN …ON 的方式实现多表的查询

SQL99 实现 内连接

语法:

SELECT table1.column, table2.column,table3.column
FROM table1JOIN table2 ON table1 和 table2 的连接条件JOIN table3 ON table2 和 table3 的连接条件
# 查询员工ID与其对应的部门名字
SELECT e.department_id,d.department_name
FROM employees e JOIN departments d 
ON e.department_id = d.department_id;
# 查询员工名字,部门,城市
SELECT e.first_name,d.department_name,l.city
FROM employees e JOIN departments d ON e.department_id = d.department_id JOIN locations l ON d.location_id = l.location_id;	

1

SQL99 实现 外连接(OUTER JOIN)

左外连接(LEFT OUTER JOIN)

语法:

#实现查询结果是A
SELECT 字段列表
FROM A表 LEFT JOIN B表
ON 关联条件
WHERE 等其他子句;

左外连接,以左边的表(A表)为主,完整的显示A表(包括不匹配的数据(为空数据也显示))

举例:

# 显示员工名字与对应部门
SELECT e.first_name,d.department_name
FROM employees e 
LEFT JOIN departments d 
ON e.department_id = d.department_id;

效果
员工有107条数据,包括为Null的,所以使用左外连接实现全显示

右外连接(RIGHT OUTER JOIN)

语法:

#实现查询结果是B
SELECT 字段列表
FROM A表 RIGHT JOIN B表
ON 关联条件
WHERE 等其他子句;

举例:

SELECT e.first_name,d.department_name
FROM employees e 
RIGHT JOIN departments d 
ON e.department_id = d.department_id;

效果
部门表中,还有很多部门没有员工,即为空

需要注意的是,LEFT JOIN 和 RIGHT JOIN 只存在于 SQL99 及以后的标准中,在 SQL92 中不存在,只能用 (+) 表示。

满外连接(FULL OUTER JOIN)

  • 满外连接的结果 = 左右表匹配的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据。
  • SQL99是支持满外连接的。使用FULL JOIN 或 FULL OUTER JOIN来实现。
  • 需要注意的是,MySQL不支持FULL JOIN,但是可以用 LEFT JOIN UNION RIGHT join代替。

UNION 和 UNION ALL的使用

UNION:会执行去重操作
UNION ALL:不会执行去重操作
结论:如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的数据,
则尽量使用UNION ALL语句,以提高数据查询的效率。

语法:

SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2

举例:

# 查询部门编号>90或邮箱包含a的员工信息
-- 方式一 -- 
SELECT *
FROM employees
WHERE department_id > 90 
OR email LIKE '%a%';
-- 方式二 --
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id > 90 ;

四、7种SQL JOINS的实现

图

1. 内连接

1

# 举例:查询员工ID名字,部门名字
SELECT e.employee_id,e.last_name,d.department_name
FROM employees e JOIN departments d ON e.department_id = d.department_id;

1

# 语法格式
SELECT 列名
FROM 表名A
JOIN 要连接的表B 
ON AB表关联字段;

2. 左外连接

2

SELECT e.employee_id,e.last_name,d.department_name
FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id;

在这里插入图片描述

#语法格式:
SELECT 列名
FROM 表名A
LEFT JOIN 表名B
ON AB关联字段;

3. 右外连接

3

# 右外连接
# 举例:查询员工ID名字,部门名字
SELECT e.employee_id,e.last_name,d.department_name
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id;

3

#语法格式:
SELECT 列名
FROM 表名A
RIGHT JOIN 表名B
ON AB关联字段;

4.左外连接 但查NULL(A - A∩B)

4
A 减去 A 交 B

# 左外连接但是查的是为Null的数值(也就是把不匹配的数据打印)
# 举例:查询员工ID名字,部门名字 为Null的
SELECT e.employee_id,e.last_name,d.department_name
FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id
WHERE d.department_id IS NULL;

在这里插入图片描述

#语法格式:
SELECT 列名
FROM 表名A
LEFT JOIN 表名B
ON AB关联字段
WHERE B.关联字段 IS NULL; -- 过滤条件:把B表为空的显示 --

5. 右外联接 但查Null(B - A∩B)

5

SELECT e.employee_id,e.last_name,d.department_name
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id
WHERE  ISNULL(e.department_id);

5

#语法格式:
SELECT 列名
FROM 表名A
RIGHT JOIN 表名B
ON AB关联字段
WHERE A.关联字段 IS NULL;-- A表为空的显示 -- 

6.满外连接 A∪B

左外连接 + 右外连接
6

SELECT e.employee_id,e.last_name,d.department_name
FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id
UNION ALL -- 不去重 --
SELECT e.employee_id,e.last_name,d.department_name
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id;

6

# 语法格式:
SELECT 列名 FROM A表 LEFT JOIN B表 ON AB关联字段
UNION (或是UNION ALL)
SELECT 列名 FROM A表 RIGHT JOIN B表 ON AB关联字段;

7. 满外连接 但是查的是Null -> (A - A∩B) ∪ (B - A∩B)

左 + 右 但是 只要不匹配数据 即为空数据
7

SELECT e.employee_id,e.last_name,d.department_name
FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id
WHERE d.department_id IS NULL
UNION ALL
SELECT e.employee_id,e.last_name,d.department_name
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id
WHERE e.employee_id IS NULL;

在这里插入图片描述

# 语法格式:
SELECT 列名 FROM A表 LEFT JOIN B表 ON AB关联字段
WHERE B表关联字段 IS NULL;
UNION (或是UNION ALL)
SELECT 列名 FROM A表 RIGHT JOIN B表 ON AB关联字段;
WHERE A表关联字段 IS NULL;

关联字段的表为空的全打印,不为空的过滤

五、SQL99 语法新特性

自然连接 NATURAL

NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中所有相同的字段,然后进行等值连接

#sql92 
# 查找员工ID,名字,部门,名字
# 关联两表 中的 部门ID 与 管理ID 
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
AND e.`manager_id` = d.`manager_id`;# sql99 自然连接
# 即把两表中所有的相同字段都关联了
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;

效果

USING连接

使用USING指定数据表里的同名字段进行等值连接。但是只能配合JOIN一起使用。
简化了代码:
1

# sql92 中也是 简化where代码
SELECT employee_id,last_name,department_name
FROM employees e ,departments d
WHERE e.department_id = d.department_id;

XG
JOIN...USING与自然连接 NATURAL JOIN 不同的是,USING 指定了具体的相同的字段名称,你需要在 USING 的括号 () 中填入要指定的同名字段

SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);

总结

表连接的约束条件可以有三种方式:WHERE, ON, USING

  • WHERE:适用于所有关联查询
  • ON:只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起写,但分开写可读性更好。
  • USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等
#关联条件
#把关联条件写在where后面
SELECT last_name,department_name 
FROM employees,departments 
WHERE employees.department_id = departments.department_id;#把关联条件写在on后面,只能和JOIN一起使用
SELECT last_name,department_name 
FROM employees INNER JOIN departments 
ON employees.department_id = departments.department_id;SELECT last_name,department_name 
FROM employees CROSS JOIN departments 
ON employees.department_id = departments.department_id;SELECT last_name,department_name  
FROM employees JOIN departments 
ON employees.department_id = departments.department_id;#把关联字段写在using()中,只能和JOIN一起使用
#而且两个表中的关联字段必须名称相同,而且只能表示=
#查询员工姓名与基本工资
SELECT last_name,job_title
FROM employees INNER JOIN jobs USING(job_id);#n张表关联,需要n-1个关联条件
#查询员工姓名,基本工资,部门名称
SELECT last_name,job_title,department_name FROM employees,departments,jobs 
WHERE employees.department_id = departments.department_id 
AND employees.job_id = jobs.job_id;SELECT last_name,job_title,department_name 
FROM employees INNER JOIN departments INNER JOIN jobs 
ON employees.department_id = departments.department_id 
AND employees.job_id = jobs.job_id;

注意:
我们要控制连接表的数量。多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。

【强制】超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时, 保证被关联的字段需要有索引。
说明:即使双表 join 也要注意表索引、SQL 性能。
来源:阿里巴巴《Java开发手册》

综合练习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度解析Pytest插件pytest-html

在软件开发中,测试报告是开发者获取测试结果和问题定位的关键工具之一。然而,标准的控制台输出有时难以满足我们对测试报告的需求。幸运的是,Pytest插件 pytest-html 提供了一种简单而强大的方式,可以生成漂亮、可视化的HTML格式测…

1992年-2020年ESA_CCI土地覆盖数据介绍、下载与数据分享

数据介绍 ESA CCI Land Cover是欧洲空间局(European Space Agency,ESA)的一个项目,其目标是生成全球土地覆盖的高质量、一致性和长期的时间序列数据,分辨率大约为300米。 该项目是ESA气候变化计划(Climate…

AI大模型学习笔记二

文章目录 一、Prompt Engineering1)环境准备 二、LangChain(一个框架名字)三、Fine-tuning(微调) 一、Prompt Engineering 1)环境准备 ①安装OpenAI库 pip install --upgrade openai附加 安装来源 pyth…

阶段十-分布式锁

5.1 节 为什么要使用分布式锁 锁是多线程代码中的概念,只有当多任务访问同一个互斥的共享资源时才需要。如下图: 在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者lock的方式来解决多线程间的代码同步问…

远程登陆利器 ssh

文章目录 远程登陆利器 ssh登陆远程服务器指定用户名多数情况的登陆方式查看服务器的时间指定端口更多信息 远程登陆利器 ssh ssh命令是openssh套件中的客户端连接工具,使用加密协议实现安全的远程登录服务器,实现对服务器的远程管理。 官方定义为&…

ZZULIOJ 1110: 最近共同祖先(函数专题)

题目描述 如上图所示,由正整数1, 2, 3, ...组成了一棵无限大的二叉树。从某一个结点到根结 点(编号是1 的结点)都有一条唯一的路径,比如从10 到根结点的路径是(10, 5, 2, 1), 从4 到根结点的路径是(4, 2, 1)&#xff0…

网络地图服务(WMS)详解

文章目录 1.概述2.GetCapabilities3.GetMap4.GetFeatureInfo 阅读本文之前可参考前文:《地图服务器GeoServer的安装与配置》与《GeoServer发布地图服务(WMS、WFS)》。 1.概述 经过前文的介绍,相信我们对WMS/WFS服务已经有了一个非…

Modbus协议学习第二篇之Modbus poll slave仿真软件初体验

软件准备 学习Modbus离不开硬件,好在我们可以通过仿真软件来模拟硬件,本篇博客就来简单介绍一下Modbus仿真软件的最基础使用方法,需要用到的3款仿真软件如下: Modbus Poll 64位 / Modbus Poll 32位(根据自己机器位数选…

C++——map和set的基本使用

目录 一,关联式容器 二,键值对 三,set的使用 3.1 set介绍 3.2 set的插入和删除 3.3 set的pair 3.4 multiset 四,map的使用 4.1 map介绍 4.2 map实现简易字典 4.3 map实现统计次数 4.4 map的[] 五,使用map或…

LV.13 D11 Linux驱动移植及内核深化 学习笔记

一、设备树 1.1 设备树 设备树是一种描述硬件信息的数据结构,Linux内核运行时可以通过设备树将硬件信息直接传递给Linux内核,而不再需要在Linux内核中包含大量的冗余编码 举例:让LED2闪烁的代码中,有逻辑代码和设备代码。Li…

案例121:基于微信小程序的作品集展示系统设计与实现

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

【模型评估 04】A/B测试的陷阱

互联网公司中,A/B测试是验证新模块、新功能、新产品是否有效;新算法、新模型的效果是否有提升;新设计是否受到用户欢迎;新更改是否影响用户体验的主要测试方法。在机器学习领域中,A/B测试是验证模型最终效果的主要手段…

C语言 - 最简单,最易懂的指针、引用讲解

一、变量、地址、变量值 二、直接上代码&#xff0c;一边看上图&#xff0c;一边讲解 #include <stdio.h>struct Hello {int a;int b; };int main() {struct Hello h;h.a 10;h.b 20;struct Hello *hp;hp &h;printf("1: h的地址是%d&#xff0c;hp地址是%d \…

stm32学习笔记:USART串口通信

1、串口通信协议&#xff08;简介软硬件规则&#xff09; 全双工&#xff1a;打电话。半双工&#xff1a;对讲机。单工&#xff1a;广播 时钟&#xff1a;I2C和SPI有单独的时钟线&#xff0c;所以它们是同步的&#xff0c;接收方可以在时钟信号的指引下进行采样。串口、CAN和…

docker完成redis 三主三从

文章目录 关闭防火墙启动docker后台服务新建6个docker容器redis实例创建并运行docker容器实例 进入容器redis-node-1并为6台机器构建集群关系链接进入6381作为切入点&#xff0c;查看集群状态主从容错切换迁移案例容错切换迁移 主从扩容案例为主节点6387分配从节点6388主从缩容…

一、MOJO环境部署和安装

以Ubuntu系统为例。 安装mojo-CLI curl https://get.modular.com | MODULAR_AUTHmut_fe303dc5ca504bc4867a1db20d897fd8 sh - 安装mojo SDK modular auth mojo modular auth install mojo 查看mojo版本号 mojo --version 输入mojo指令&#xff0c;进入交互编程窗口

On the Robustness of Backdoor-based Watermarkingin Deep Neural Networks

关于深度神经网络中基于后门的数字水印的鲁棒性 ABSTRACT 在过去的几年中&#xff0c;数字水印算法已被引入&#xff0c;用于保护深度学习模型免受未经授权的重新分发。我们调查了最新深度神经网络水印方案的鲁棒性和可靠性。我们专注于基于后门的水印技术&#xff0c;并提出了…

6、C语言:输入与输出

输入输出 标准输入输出getchar&putchar函数printf函数sprintf函数格式化输入——scanf函数 文件访问文件读写 错误处理&#xff1a;stderr和exit行输入和行输出常用函数字符串操作函数字符类别测试和转换函数存储管理函数数学函数随机数发生器函数其他 标准输入输出 getch…

2024年【氧化工艺】免费试题及氧化工艺作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 氧化工艺免费试题根据新氧化工艺考试大纲要求&#xff0c;安全生产模拟考试一点通将氧化工艺模拟考试试题进行汇编&#xff0c;组成一套氧化工艺全真模拟考试试题&#xff0c;学员可通过氧化工艺作业模拟考试全真模拟…

洛谷 P1439 【模板】最长公共子序列【线性dp+dp模型转换】

原题链接&#xff1a;https://www.luogu.com.cn/problem/P1439 题目描述 给出 1,2,…,n 的两个排列 P1​ 和 P2​ &#xff0c;求它们的最长公共子序列。 输入格式 第一行是一个数 n。 接下来两行&#xff0c;每行为 n 个数&#xff0c;为自然数 1,2,…,n 的一个排列。 输…