数据库基础——7.多表查询

news2024/12/26 22:30:37

这篇文章来讲一下数据库中的多表查询

目录

1. 一个案例引发的多表连接

1.1 案例说明

1.2 笛卡尔积(或交叉连接)的理解

1.3 案例分析与问题解决

2. 多表查询分类讲解

2.1 等值连接 vs 非等值连接

2.1.1等值连接

2.1.2 非等值连接

2.2 自连接 vs 非自连接 

2.3 内连接 vs 外连接 

3.实现多表查询

3.1 基本语法

3.2 内连接(INNER JOIN)的实现

3.3 外连接(OUTER JOIN)的实现 

3.3.1 左外连接(LEFT OUTER JOIN)

3.3.2 右外连接(RIGHT OUTER JOIN) 

3.3.3 满外连接(FULL OUTER JOIN)

4. UNION的使用

5. 7种SQL JOINS的实现 

5.1 代码实现

5.2 语法格式小结

6. SQL99语法新特性

6.1 自然连接

6.2 USING连接

7. 章节小结


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

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

1. 一个案例引发的多表连接

1.1 案例说明

从多个表中获取数据:

 

#案例:查询员工的姓名及其部门名称

SELECT last_name, department_name FROM employees, departments; 

 分析错误情况:

 SELECT COUNT(employee_id) FROM employees;

#输出107行

SELECT COUNT(department_id)FROM departments;

#输出27行

SELECT 107*27 FROM dual;

我们把上述多表查询中出现的问题称为:笛卡尔积的错误。 

1.2 笛卡尔积(或交叉连接)的理解

笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素 个数的乘积数。

SQL92中,笛卡尔积也称为 交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交 叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。在MySQL中如下情况会出现笛卡尔积:

 #查询员工姓名和所在部门名称

SELECT last_name,department_name FROM employees,departments;

SELECT last_name,department_name FROM employees CROSS JOIN departments; SELECT last_name,department_name FROM employees INNER JOIN departments; SELECT last_name,department_name FROM employees JOIN departments;

为什么会引发迪卡尔积?因为你没有加限制条件,那么关联查询时就是按笛卡尔积的形式来查。如何解决迪卡尔积?加上关联条件即可。 

1.3 案例分析与问题解决

笛卡尔积的错误会在下面条件下产生:

  • 省略多个表的连接条件(或关联条件)
  • 连接条件(或关联条件)无效
  • 所有表中的所有行互相连接

为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件

加入连接条件后,查询语法:

SELECT table1.column, table2.column

FROM table1, table2

WHERE table1.column1 = table2.column2;    #连接条件

在 WHERE子句中写入连接条件。

上述问题的正确写法: 

#案例:查询员工的姓名及其部门名称

SELECT last_name, department_name

FROM employees, departments

WHERE employees.department_id = departments.department_id

2. 多表查询分类讲解

2.1 等值连接 vs 非等值连接

2.1.1等值连接

解释:就是两张表中有相同的属性,然后如果这两个属性中的值也相同,那么就根据这个属性把这两张表给连接起来

例:SELECT employees.employee_id, employees.last_name, employees.department_id, departments.department_id, departments.location_id FROM employees, departments WHERE employees.department_id = departments.department_id;

拓展1. 多个连接条件与 AND 操作符

拓展2:区分重复的列名

多个表中有相同列时,必须在列名之前加上表名前缀

在不同表中具有相同列名的列可以用 表名 加以区分

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

拓展3:表的别名 

使用别名可以简化查询。 列名前使用表名前缀可以提高查询效率

例:SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id FROM employees e , departments d WHERE e.department_id = d.department_id;

注意:如果我们使用了表的别名,在查询字段中、过滤条件中就只能使用别名进行代替, 不能使用原有的表名,否则就会报错。

拓展4:连接多个表

总结:连接 n个表,至少需要n-1个连接条件。比如,连接三个表,至少需要两个连接条件。 

2.1.2 非等值连接

例:SELECT 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.2 自连接 vs 非自连接 

说明:当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询。 

例:SELECT CONCAT(worker.last_name ,' works for ' , manager.last_name) FROM employees worker, employees manager WHERE worker.manager_id = manager.employee_id ;

2.3 内连接 vs 外连接 

除了查询满足条件的记录以外,外连接还可以查询某一方不满足条件的记录。

内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行 

外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的 行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

  • 如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表
  • 如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表

在 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 中,只有左外连接和右外连接,没有满(或全)外连接。

3.实现多表查询

3.1 基本语法

使用JOIN...ON子句创建连接的语法结构:

SELECT table1.column, table2.column,table3.column

        FROM table1

                JOIN table2 ON table1 和 table2 的连接条件

                        JOIN table3 ON table2 和 table3 的连接条件

它的嵌套逻辑类似我们使用的 FOR 循环:

for t1 in table1:

        for t2 in table2:

                if condition1:

                        for t3 in table3:

                                if condition2:

                                        output t1 + t2 + t3

SQL采用的这种嵌套结构非常清爽、层次性更强、可读性更强,即使再多的表进行连接也都清晰 可见。

语法说明:

  • 可以使用 ON 子句指定额外的连接条件。
  • 这个连接条件是与其它条件分开的。
  • ON 子句使语句具有更高的易读性。
  • 关键字 JOIN、INNER JOIN、CROSS JOIN 的含义是一样的,都表示内连接

3.2 内连接(INNER JOIN)的实现

语法:

SELECT 字段列表

FROM A表

INNER JOIN B表 ON 关联条件

WHERE 等其他子句;

例:SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id FROM employees e JOIN departments d ON (e.department_id = d.department_id);

例:SELECT employee_id, city, department_name FROM employees e JOIN departments d ON d.department_id = e.department_id JOIN locations l ON d.location_id = l.location_id;

3.3 外连接(OUTER JOIN)的实现 

3.3.1 左外连接(LEFT OUTER JOIN)

语法:

#实现查询结果是A

SELECT 字段列表

FROM A表

LEFT JOIN B表

ON 关联条件

WHERE 等其他子句;

例:SELECT e.last_name, e.department_id, d.department_name FROM employees e LEFT OUTER JOIN departments d ON (e.department_id = d.department_id) ;

3.3.2 右外连接(RIGHT OUTER JOIN) 

语法:

#实现查询结果是B

SELECT 字段列表

FROM A表

RIGHT JOIN B表

ON 关联条件

WHERE 等其他子句;

例:SELECT e.last_name, e.department_id, d.department_name FROM employees e RIGHT OUTER JOIN departments d ON (e.department_id = d.department_id) ;

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

3.3.3 满外连接(FULL OUTER JOIN)

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

4. UNION的使用

合并查询结果 利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION ALL关键字分隔。

语法:

SELECT column,... FROM table1

UNION [ALL]

SELECT column,... FROM table2

 UNION操作符

UNION 操作符返回两个查询的结果集的并集,去除重复记录。

UNION ALL操作符 

UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。

注意:执行UNION ALL语句时所需要的资源比UNION语句少。如果明确知道合并数据后的结果数据 不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效率。 

例:SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;

方式2:SELECT * FROM employees WHERE email LIKE '%a%' UNION SELECT * FROM employees WHERE department_id>90;

5. 7种SQL JOINS的实现 

 

5.1 代码实现

 #中图:内连接 A∩B

SELECT employee_id,last_name,department_name

FROM employees e JOIN departments d

ON e.`department_id` = d.`department_id`;

#左上图:左外连接

SELECT employee_id,last_name,department_name

FROM employees e LEFT JOIN departments d

ON e.`department_id` = d.`department_id`;

#右上图:右外连接

SELECT employee_id,last_name,department_name

FROM employees e RIGHT JOIN departments d

ON e.`department_id` = d.`department_id`;

#左中图:A - A∩B

SELECT employee_id,last_name,department_name

FROM employees e LEFT JOIN departments d

ON e.`department_id` = d.`department_id` WHERE d.`department_id` IS NULL

#右中图:B-A∩B

SELECT employee_id,last_name,department_name

FROM employees e RIGHT JOIN departments d

ON e.`department_id` = d.`department_id` WHERE e.`department_id` IS NULL

#左下图:满外连接 # 左中图 + 右上图 A∪B

SELECT employee_id,last_name,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 employee_id,last_name,department_name

FROM employees e RIGHT JOIN departments d

ON e.`department_id` = d.`department_id`;

#右下图 #左中图 + 右中图 A ∪B- A∩B 或者 (A - A∩B) ∪ (B - A∩B)

SELECT employee_id,last_name,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 employee_id,last_name,department_name

FROM employees e RIGHT JOIN departments d

ON e.`department_id` = d.`department_id`

WHERE e.`department_id` IS NULL

5.2 语法格式小结

#左中图 实现A - A∩B

select 字段列表

from A表 left join B表

on 关联条件

where 从表关联字段 is null and 等其他子句;

#右中图  实现B - A∩B

select 字段列表

from A表 right join B表

on 关联条件

where 从表关联字段 is null and 等其他子句;

#左下图  实现查询结果是A∪B

#用左外的A,union 右外的B

select 字段列表

from A表 left join B表

on 关联条件

where 等其他子句

union

select 字段列表

from A表 right join B表

on 关联条件

where 等其他子句

#右下图 实现A∪B - A∩B 或 (A - A∩B) ∪ (B - A∩B)

#使用左外的 (A - A∩B) union 右外的(B - A∩B)

select 字段列表

from A表 left join B表

on 关联条件

where 从表关联字段 is null and 等其他子句

union

select 字段列表

from A表 right join B表

on 关联条件

where 从表关联字段 is null and 等其他子句

6. SQL99语法新特性

6.1 自然连接

SQL99 在 SQL92 的基础上提供了一些特殊语法,比如 NATURAL JOIN 用来表示自然连接。我们可以把 自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中所有相同的字段,然后进行等值连接 。

在SQL92标准中:

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;

6.2 USING连接

当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的 同名字段 进行等值连接。但是只能配合JOIN一起使用。比如:

SELECT employee_id,last_name,department_name

FROM employees e JOIN departments d

USING (department_id);

你能看出与自然连接 NATURAL JOIN 不同的是,USING 指定了具体的相同的字段名称,你需要在 USING 的括号 () 中填入要指定的同名字段。同时使用 JOIN...USING 可以简化 JOIN ON 的等值连接。它与下面的 SQL 查询结果是相同的:

SELECT employee_id,last_name,department_name

FROM employees e ,departments d

WHERE e.department_id = d.department_id;

7. 章节小结

表连接的约束条件可以有三种方式: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 中,也都会有最大连接表的限制。

 

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

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

相关文章

chatgpt赋能python:PythonDemo:快速了解Python编程语言

Python Demo:快速了解Python编程语言 如果你是一个对编程感兴趣的人,或者正在学习编程,那么你一定听说过Python这个编程语言。Python是一个非常易学易用的语言,同时也是非常流行的语言之一。Python具有众多的库和框架&#xff0c…

从RE到RSE:聊聊无线产品EMC认证测试中的辐射项(下)

当无线产品开启个人通信时代之际,EUT这个载体变了,辐射发射测试标准要不要变?怎么变? 回答这个问题的不再是ANSI和CISPR,而是联合国下属机构国际电信联盟无线电通信部门(ITU-R)以及著名的移动通…

Django学习笔记002之resetfull应用

学习目标: 学习resetfull接口 掌握Django web基础设施 学习内容: 1.学习resetfull接口 简介 人工智能解释: 应用场景 以下是人工智能使用Django框架实现的restfull接口代码: #views.py from django.http import JsonRespon…

maven环境变量配置zsh: command not found: mvn。

在输入命令vim ~/.zshrc的时候出现下面的报错: 解决办法 第一步输入下面的命令vim -r 文件名(文件名也就是第二行双引号里面的所有字母字符) 第二步输入下面的命令rm -f xx.swp 在配置好maven的环境变量但是在输入mvn -v的时候会报错 zsh:…

浅读《简约之美-软件设计之道》

浅读《简约之美-软件设计之道》 大家好,我是Lampard~ 这个周末阅读了一本程序设计相关的书籍《简约之美-软件设计之道》,它原著是《The Science of Software Development》,由余晟大大翻译。 这本书只有数十页,和它的命名一样追求…

Linux---GUN binutils

文章目录 一、GUN binutis概述二、工具集详细说明nm指令使用size指令使用objdump指令使用addr2line指令使用readelf指令使用strip指令使用 一、GUN binutis概述 什么是GUN binutis?它是一个二进制工具集,默认情况下所有 Linux 发行版中都会安装这些二进制工具。实际…

chatgpt赋能python:Python中的Cumsum()函数

Python中的Cumsum()函数 Python是数据科学家和工程师喜欢的一种高级脚本语言。它为许多数据科学的任务提供了大量的分析和可视化工具。 在Python中,Cumulative Sum或cumsum()函数是一个非常有用的函数之一。 它可以基于给定的轴计算数组元素的累积和。 什么是cums…

【牛客算法BM2】 链表内指定区间反转

​ 你好,欢迎来到我的博客!作为一名程序员,我经常刷LeetCode题目来提升自己的编程能力。在我的博客里,我会分享一些我自己做过的题目和解题思路,希望能够帮助到大家。今天,我想和大家分享一道挑战性较高的题…

chatgpt赋能python:Python编程技巧:没有换行输入三个数的方法

Python编程技巧:没有换行输入三个数的方法 在Python编程过程中,我们经常需要从用户输入一些数据。但是,当我们需要从用户输入多个数值时,我们往往会遇到一些问题,比如输入回车符会造成程序无法正常执行等。那么&#…

被比尔盖茨选中的GPT技术,是如何演进,又革谁的命?

作者 | 智商掉了一地、Python 如果机器能够以类似于人类的方式进行理解和沟通,那会是怎样的情况?这一直是学界中备受关注的话题,而由于近些年来在自然语言处理的一系列突破,我们可能比以往任何时候都更接近实现这个目标。在这个突…

C语言基础:翁恺笔记

英尺英寸换算米案例&#xff1a; #include <stdio.h>int main() {int inch0,foot0;printf("请输入身高的英尺和英寸\n");scanf("%d %d",&inch,&foot);printf("身高是%f米",(inchfoot/12)*0.3048);return 0; } 总结&#xff1a;…

mac的maven的环境变量配置

首先下载maven文件 下载安装 下载地址&#xff1a; Maven – Download Apache Maven 2、配置环境变量 打开mac终端&#xff0c;不做任何操作直接输入命令&#xff1a;vim ~/.zshrc 打开.zshrc之后&#xff0c;按下i键&#xff0c;进行配置如下&#xff1a; #maven export M…

chatgpt赋能python:Python下载与运行指南-让Python脚本更容易使用

Python下载与运行指南 - 让Python脚本更容易使用 Python已经成为世界上最流行的编程语言之一。Python具有简单易用的特点&#xff0c;几乎可以开始创建任何类型的应用程序或脚本。如果你是一名新手或是一名经验丰富的开发者&#xff0c;Python都是一款优秀的编程语言。 本篇文…

chatgpt赋能python:Python中KW的介绍:了解Python关键字

Python中KW的介绍&#xff1a;了解Python关键字 在Python语言中&#xff0c;KW是一个非常重要的概念。KW是Python中的关键字&#xff0c;也就是非常重要的语法元素。在程序中使用正确的KW可以帮助我们避免一些常见的错误&#xff0c;从而提高代码的可读性和运行效率。本文将对…

list常见接口的使用(基于c++标准库中的STL)

前言 list是重要的容器了解它的常见接口以及使用是很有必要的&#xff0c;为什么有了vector还要有list呢&#xff1f;因为vector存在一些缺陷&#xff0c;比如&#xff1a;容量满了要扩容&#xff0c;扩容是要付出代价的&#xff08;性能的损失&#xff09;&#xff0c;存在空…

【Leetcode -724.寻找数组的中心下标 -728.自除数】

Leetcode Leetcode -724.寻找数组的中心下标Leetcode -728.自除数 Leetcode -724.寻找数组的中心下标 题目&#xff1a;给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的…

【网络编程】一文详解http协议(超文本传输协议)

目录 一、http协议 1、http协议的介绍 2、URL的组成 3、urlencode和urldecode 二、http的请求方法、状态码及状态码描述、常见的响应报头 1、http请求方法 2、http状态码及状态码描述 3、http常见的响应报头 三、http协议客户端和服务器的通信过程 1、如何保证请求和…

驱动LSM6DS3TR-C实现高效运动检测与数据采集(2)----配置滤波器

工作模式 在LSM6DS3TR-C中&#xff0c;加速度计和陀螺仪可以独立地开启/关闭&#xff0c;并且可以拥有不同的ODR和功耗模式。 LSM6DS3TR-C有三种可用的操作模式&#xff1a; ● 仅加速度计活动&#xff0c;陀螺仪处于断电状态 ● 仅陀螺仪活动&#xff0c;加速度计处于断电状态…

chatgpt赋能python:Python中0.2+0.1的问题解决方案

Python中0.20.1的问题解决方案 在Python中&#xff0c;0.20.1的结果并非等于0.3。这是由于计算机在二进制中存储小数时会存在精度问题导致的。而这个问题在日常编程中可能并不会带来太大的影响&#xff0c;但在需要精确计算的场景下&#xff0c;如金融或科学领域&#xff0c;就…

第 2 章:Vue 组件化编程

目录 模块与组件、模块化与组件化 模块 组件 模块化 组件化 非单文件组件 小结 组件的几个注意点 组件的嵌套 VueComponent构造函数 小结 一个重要的内置关系 小结 单文件组件 一个.vue 文件的组成(3 个部分) 1. 模板页面 2. JS 模块对象 3. 样式 基本使用 模…