首页 > 数据库 >MySQL中的四种表联结

MySQL中的四种表联结

时间:2025-01-13 16:05:31浏览次数:3  
标签:cust -- 联结 SELECT MySQL prod id 四种

目录

1、联结、关系表

(1)关系表

(2)为什么使用联结

2、如何创建联结

(1)笛卡尔积(叉联结)--用逗号分隔

(2)where子句的重要性

(3)内联结--INNER JOIN 

(4)联结多个表

3、使用表别名(对比列别名)

4、自联结、自然联结、外联结

(1)自联结:self-join

(2)自然联结:natural join

(3)外联结:left join、right join

5、使用带聚集函数的联结

6、使用联结和联结条件

7、小结


博主用的是mysql8 DBMS,附上示例资料:

百度网盘链接: https://pan.baidu.com/s/1XaWi3Y7hpXbs_uHq2cPI6Q

提取码: fpnx

1、联结、关系表

SQL 最强大的功能之一就是能在数据查询的执行中联结(join)表。联结是利用 SQL 的 SELECT 能执行的最重要的操作,很好地理解联结及其语法是学习 SQL 的极为重要的部分。

在能够有效地使用联结前,必须了解关系表以及关系数据库设计的一些基础知识。下面的介绍并不能涵盖这一主题的所有内容,但作为入门已经够了。

(1)关系表

理解关系表,最好是来看个例子。

有一个包含产品目录的数据库表,其中每类物品占一行。对于每一种物品,要存储的信息包括产品描述、价格,以及生产该产品的供应商。现在有同一供应商生产的多种物品,那么在何处存储供应商名、地址、联系方法等供应商信息呢?将这些数据与产品信息分开存储的理由是:

  • 同一供应商生产的每个产品,其供应商信息都是相同的,对每个产品重复此信息既浪费时间又浪费存储空间;
  • 如果供应商信息发生变化,例如供应商迁址或电话号码变动,只需修改一次即可
  • 如果有重复数据(即每种产品都存储供应商信息),则很难保证每次输入该数据的方式都相同。不一致的数据在报表中就很难利用。

关键是,相同的数据出现多次决不是一件好事,这是关系数据库设计的基础。关系表的设计就是要把信息分解成多个表,一类数据一个表。各表通过某些共同的值互相关联(所以才叫关系数据库)。

在这个例子中可建立两个表:一个存储供应商信息,另一个存储产品信息。Vendors 表包含所有供应商信息,每个供应商占一行,具有唯一的标识。此标识称为主键(primary key),可以是供应商 ID 或任何其他唯一值。

Products 表只存储产品信息,除了存储供应商 ID(Vendors 表的主键)外,它不存储其他有关供应商的信息。Vendors 表的主键将 Vendors 表与 Products 表关联,利用供应商 ID 能从 Vendors 表中找出相应供应商的详细信息。

这样做的好处是:

  • 供应商信息不重复,不会浪费时间和空间;
  • 如果供应商信息变动,可以只更新 Vendors 表中的单个记录,相关表中的数据不用改动;
  • 由于数据不重复,数据显然是一致的,使得处理数据和生成报表更简单。

总之,关系数据可以有效地存储,方便地处理。因此,关系数据库的可伸缩性远比非关系数据库要好。

可伸缩(scale)

能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称为可伸缩性好(scale well)。

(2)为什么使用联结

如前所述,将数据分解为多个表能更有效地存储,更方便地处理,并且可伸缩性更好。但这些好处是有代价的。 如果数据存储在多个表中,怎样用一条 SELECT 语句就检索出数据呢?

答案是使用联结。简单说,联结是一种机制,用来在一条 SELECT 语句中关联表,因此称为联结。使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。

2、如何创建联结

(1)笛卡尔积(叉联结)--用逗号分隔

创建一个联结非常简单,指定要联结的所有表以及关联它们的方式即可

比如查找供应商名、对应的prod_name、prod_price:

-- 查找供应商名、对应的prod_name、prod_price
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id;
-- 联结的操作在FROM中执行,连接后(笛卡尔积)有6*14行,再经过vend_id进行过滤

SELECT 语句与前面所有语句一样指定要检索的列。这里最大的差别是所指定的两列(prod_name 和 prod_price)在一个表中,而第三列(vend_name)在另一个表中。

这条语句的 FROM子句列出了两个表:Vendors 和 Products。它们就是这条 SELECT 语句联结的两个表的名字。这里的联结方式是逗号“,”,代表笛卡尔积,后续的WHERE用于筛选满足条件的行。

可以看到,要匹配的两列指定为 Vendors.vend_id 和 Products.vend_id。这里需要这种完全限定列名,如果只给出 vend_id,DBMS 就不知道指的是哪一个(每个表中有一个)。

警告:完全限定列名

就像前一课提到的,在引用的列可能出现歧义时,必须使用完全限定列名(用一个句点分隔表名和列名)。如果引用一个没有用表名限制的具有歧义的列名,大多数 DBMS 会返回错误。

(2)where子句的重要性

举例,没有利用where进行过滤时:结果就是两个表的笛卡尔积。

SELECT *
FROM vendors, products

笛卡儿积(cartesian product)

由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

相应的笛卡儿积不是我们想要的。这里返回的数据用每个供应商匹配了每个产品,包括了供应商不正确的产品(即使供应商根本就没有产品)。

注意:不要忘了 WHERE 子句

要保证所有联结都有 WHERE 子句,否则 DBMS 将返回比想要的数据多得多的数据。同理,要保证 WHERE 子句的正确性。不正确的过滤条件会导致 DBMS 返回不正确的数据。

提示:叉联结(×):有时,返回笛卡儿积的联结,也称叉联结(cross join)。

(3)内联结--INNER JOIN 

上面使用叉联结+WHERE过滤后的结果与等值联结的结果相同。

等值联结(equijoin,它基于两个表之间的相等测试。这种联结也称为内联结(inner join)。其实,可以对这种联结使用稍微不同的语法,明确指定联结的类型。下面的 SELECT 语句返回与前面例子完全相同的数据:

-- 目前为止使用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内联结(inner join)。
SELECT vend_name, prod_name, prod_price 
FROM Vendors INNER JOIN Products 
ON Vendors.vend_id = Products.vend_id
-- 在使用这种语法时,联结条件用特定的 ON 子句而不是 WHERE 子句给出。
WHERE prod_price > 5;
  • 内联结使用INNER JOIN来连接两个表,ON子句指定连接的条件,在这里是一种等值条件,意味着满足条件的行才会进行联结。
  • 如果没有ON子句,联结的结果就是叉积的结果。
  • ON用于指定联结的条件,是在联结之前进行,WHERE只起到过滤的作用,在联结之后进行

(4)联结多个表

  • 叉积用逗号分隔即可
  • 内联结用INNER JOIN分隔即可

联结多个表,查找20005号订单的各个产品名、生产商名、价格和数量

-- 联结多个表,查找20005号订单的各个产品名、生产商名、价格和数量
-- 内联结+ON条件联结+where过滤方式(只用ON或者where也可)
SELECT prod_name, vend_name, prod_price, quantity 
FROM OrderItems INNER JOIN Products INNER JOIN Vendors  
ON orderitems.prod_id = products.prod_id
 AND products.vend_id = vendors.vend_id
WHERE order_num = 20005;

-- 叉积过滤方式
SELECT prod_name, vend_name, prod_price, quantity
FROM vendors, orderitems, products
WHERE order_num = '20005'
 AND vendors.vend_id = products.vend_id
 AND orderitems.prod_id = products.prod_id 

注意:性能考虑

DBMS 在运行时关联指定的每个表,以处理联结。这种处理可能非常耗费资源,因此应该注意,不要联结不必要的表。联结的表越多,性能下降越厉害。

需要列出订购物品号 ANV01 的所有顾客的名字和联系名 

-- 需要列出订购物品号 ANV01 的所有顾客的名字和联系名
SELECT cust_name, cust_contact
FROM orderitems INNER JOIN orders INNER JOIN customers
ON orderitems.order_num = orders.order_num
 AND orders.cust_id = customers.cust_id
WHERE prod_id = 'ANV01';

3、使用表别名(对比列别名)

SQL 除了可以对列名和计算字段使用别名,还允许给表名起别名。这样做有两个主要理由:

  • 缩短 SQL 语句;
  • 允许在一条 SELECT 语句中多次使用相同的表。

请看下面的 SELECT 语句。它与前一课例子中所用的语句基本相同,但改成了使用别名:

联结多个表,查找20005号订单的各个产品名、生产商名、价格和数量

-- 表别名,与列或者计算字段别名不同,在FROM中进行
-- 联结多个表,查找20005号订单的各个产品名、生产商名、价格和数量
SELECT prod_name, vend_name, prod_price, quantity 
FROM OrderItems AS O INNER JOIN Products AS P INNER JOIN Vendors AS V
ON O.prod_id = P.prod_id
 AND P.vend_id = V.vend_id
WHERE order_num = 20005;

可以看到,FROM 子句中的三个表全都有别名。Customers AS C 使用 C作为 Customers 的别名,如此等等。这样,就可以使用省略的 C 而不用全名 Customers。在这个例子中,表别名只用于 WHERE 子句。其实它不仅能用于 WHERE 子句,还可以用于 SELECT 的列表、ORDER BY 子句以及其他语句部分。  

4、自联结、自然联结、外联结

(1)自联结:self-join

前面所提的表别名的一个主要原因就是在一个select语句中多次使用同一个表。

而自联结就是将表自身联结起来:例如在customers中找到与 Jim Jones 同一公司的所有顾客:

  • 容易想到使用子查询方式:
-- 找到与 Jim Jones 同一公司的所有顾客
-- 子查询方式
SELECT cust_id, cust_name, cust_contact, cust_email
FROM customers
WHERE cust_name = (SELECT cust_name
					FROM customers
					WHERE cust_contact = 'Jim Jones');
  • 使用自联结呢?--其实就是内联结或者笛卡尔积,不过两个表都是同一个表(使用笛卡尔积也可以)。
-- 自联结,就是将利用表别名将表本身进行内联结或者笛卡尔积
SELECT C1.cust_id, C1.cust_name, C1.cust_contact, C1.cust_email
FROM customers AS C1 INNER JOIN customers AS C2
ON C2.cust_contact = 'Jim Jones'
WHERE C1.cust_name = C2.cust_name;
-- 利用ON先将C2过滤得只剩两行再进行内联结
-- 联结后再利用where进行过滤将C1的cust_name与C2的cust_name进行匹配筛选

此查询中需要的两个表实际上是相同的表,因此 Customers 表在 FROM子句中出现了两次。虽然这是完全合法的,但对 Customers 的引用具有歧义性,因为 DBMS 不知道你引用的是哪个 Customers 表。

解决此问题,需要使用表别名。Customers 第一次出现用了别名 C1,第二次出现用了别名 C2。现在可以将这些别名用作表名。例如,SELECT 语句使用 C1 前缀明确给出所需列的全名。如果不这样,DBMS 将返回错误,因为名为 cust_id、cust_name、cust_contact 的列各有两个。DBMS不知道想要的是哪一列(即使它们其实是同一列)。

提示:用自联结而不用子查询

自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查询语句。虽然最终的结果是相同的,但许多 DBMS 处理联结远比处理子查询快得多。应该试一下两种方法,以确定哪一种的性能更好。

(2)自然联结:natural join

  • 经过前面的练习,不难知道联结之后的结果难免出现相同的列,自然联结就是排除列的多次出现,使得每列只返回一次。
  • 怎样完成这项工作呢?答案是,系统不完成这项工作,由你自己完成它。也就是自己指定检索出的列名。一般通过对一个表使用通配符(SELECT *),而对其他表的列使用明确的子集来完成。
-- 自然联结,想要消除内联结导致重复的列,系统无法做到,只能人工完成
-- 需要列出订购物品号 ANV01 的所有顾客的信息,包括订单信息,但不重复列
SELECT C.*, 
		O.order_num, O.order_date, 
		OI.order_item, OI.prod_id, OI.item_price, OI.quantity
FROM orders AS O 
 INNER JOIN orderitems AS OI 
 INNER JOIN customers AS C
ON OI.prod_id = 'ANV01'
 AND OI.order_num = O.order_num
 AND O.cust_id = C.cust_id;
-- 把ON换成WHERE效果是一样的,但是进行联结的时候不一样哦
-- WHERE是对联结的结果进行过滤,ON是在联结前设置条件

(3)外联结:left join、right join

 许多联结将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。例如,可能需要使用联结完成以下工作:

  • 对每个顾客下的订单进行计数,包括那些至今尚未下订单的顾客;
  • 列出所有产品以及订购数量,包括没有人订购的产品;
  • 计算平均销售规模,包括那些至今尚未下订单的顾客。

在上述例子中,联结包含了那些在相关表中没有关联行的行。这种联结称为外联结。

举例更好理解,比如使用内联结查看已有顾客的订单数量(这些顾客至少有订单)

SELECT customers.cust_id, COUNT(*)
FROM orders INNER JOIN customers
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

这里的结果是满足的,但是如果我想要所有顾客的订单信息呢?(包括没有订单的顾客)就需要使用外联结了。

  • 在使用 OUTER JOIN 语法时,必须使用 RIGHT 或 LEFT 关键字指定包括其所有行的表(RIGHT 指出的是 OUTER JOIN 右边的表,而 LEFT 指出的是 OUTER JOIN左边的表)
-- 由于这些顾客在orders中没有行记录相应的id,就需要联结在相关表中没有关联的行,这就是外联结
SELECT customers.cust_id, COUNT(orders.order_num)
FROM customers LEFT JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;
-- 因为有些顾客实际上没有订单,所以应该计数order_num
-- 还有一种叫全联结,但MySQL不允许

上面的例子使用 LEFT JOIN 从 FROM 子句左边的表(Customers 表)中选择所有行。为了从右边的表中选择所有行,需要使用 RIGHT JOIN,如下例所示:

SELECT customers.cust_id, COUNT(orders.order_num)
FROM orders RIGHT JOIN  customers 
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

 还存在另一种外联结,就是全外联结(full outer join),它检索两个表中的所有行并关联那些可以关联的行。与左外联结或右外联结包含一个表的不关联的行不同,全外联结包含两个表的不关联的行。但是MYSQL不支持全联结

5、使用带聚集函数的联结

  • 上面的例子已经可以看到我们使用了GROUP BY语句。也就是说,聚集函数也可以方便地与其他联结一起使用。
  • 粗糙一点的话,将联结后的结果看作表就好啦。

6、使用联结和联结条件

汇总一下联结及其使用的要点。

  • 注意所使用的联结类型。一般我们使用内联结,但使用外联结也有效。
  • 关于确切的联结语法,应该查看具体的文档,看相应的 DBMS 支持何种语法(大多数 DBMS 使用这两课中描述的某种语法)。
  • 保证使用正确的联结条件(不管采用哪种语法),否则会返回不正确的数据。
  • 应该总是提供联结条件,否则会得出笛卡儿积
  • 在一个联结中可以包含多个表,甚至可以对每个联结采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前分别测试每个联结。这会使故障排除更为简单

7、小结

  1. 联结表时尽量用完全限定名,避免歧义;有时候经常需要联结多个表,注意数量。
  2. 叉积使用逗号分隔,where用于过滤联结之后的行,没有指定条件的内联结就是笛卡尔积。
  3. 内联结使用INNER JOIN分隔,联结前ON子句可指定联结条件,注意与where区分。
  4. 使用表别名,可以缩短我们的代码,也可以用于自联结。
  5. 自联结就是对相同的表利用表别名来进行联结操作,至于采用何种联结取决于自己。
  6. 在进行联结时难免出现重复的列,自然联结的要求就是消除重复列,不过只能自己操作,一般是取一个表的*和其他表的列。
  7. 外联结用于解决统计某些不包含在统计表中的场景,比如统计所有顾客的订单量(即使顾客没有订单)。
  8. 使用联结后同样可以进行分组操作,也能使用聚集函数。

标签:cust,--,联结,SELECT,MySQL,prod,id,四种
From: https://blog.csdn.net/i_cant_qiao_chu/article/details/145113909

相关文章

  • JAVA开源毕业设计 共享汽车管理系统 Vue.JS+SpringBoot+MySQL
    本文项目编号T125,文末自助获取源码\color{red}{T125,文末自助获取源码}......
  • JAVA开源毕业设计 计算机课程管理平台 Vue.JS+SpringBoot+MySQL
    本文项目编号T126,文末自助获取源码\color{red}{T126,文末自助获取源码}......
  • Mysql身份认证过程
    背景最近有一些hersql的用户希望能支持mysql的caching_sha2_password认证方式,caching_sha2_password与常用的mysql_native_password认证过程差异还是比较大的,因此抽空研究了一下caching_sha2_password身份认证过程,并为hersql支持了caching_sha2_password的能力hersql是我开源的......
  • MYSQL----------------sql 优化
    优化SQL语句的一般步骤1.了解SQL的执行频率SHOWSTATUSLIKE'Com_%';代码解释:SHOWSTATUSLIKE'Com_%';:此命令可以查看各种SQL语句的执行频率,例如Com_select表示SELECT语句的执行次数,Com_insert表示INSERT语句的执行次数等。通过查看这些信息,可以大致......
  • MYSQL--------SQL 注入简介&&MySQL SQL Mode 简介
    SQL注入简介定义:SQL注入是一种常见的安全漏洞,攻击者通过在输入中插入恶意的SQL语句,利用应用程序中未正确处理的输入数据,来改变SQL查询的逻辑,从而执行非预期的操作,如绕过身份验证、获取未授权数据、修改或删除数据等。示例:--正常的登录查询SELECT*FROMusersWHE......
  • Mysql--运维篇--库表分离(垂直分库,水平分库,垂直分表,水平分表)
    在处理大规模数据和高并发访问时,数据库的分库和分表是两种常见的优化策略。它们通过将数据分散到多个数据库或表中,来提高性能、可扩展性和管理效率。为了更精细地应对不同的场景,分库和分表可以进一步细分为垂直分库/分表和水平分库/分表。一、分库(DatabaseSharding)分库是......
  • MySQL备份工具mydumper下载(RPM方式)安装以及详细使用教程
    1、mydumper工具介绍        mydumper是一款社区开源的,用于MySQL数据库的高性能多线程备份工具。与传统的mysqldump相比,mydumper提供了更快的备份和恢复速度,特别是在处理大型数据库时。它包含两个主要工具:•mydumper:负责导出一致的MySQL数据库备份。•myl......
  • MySQL不使用子查询的原因
    MySQL不使用子查询的原因及优化案例目录MySQL不使用子查询的原因及优化案例目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EXISTS优化子查询案例3:使用JOIN代替子查询案例4:优化子查询以减少数据量案例5:使用索引覆盖案例6:使用......
  • (免费送源码)计算机毕业设计原创定制:Java+springboot+MySQL springboot 第三方游戏账号
    摘要本论文主要论述了如何使用JAVA语言开发一个springboot第三方游戏账号交易平台,本系统将严格按照软件开发流程进行各个阶段的工作,采用springboot+vue.js相结合框架,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述第三方游戏账号交易平台的当前背景以及系统......
  • (免费送源码)计算机毕业设计原创定制:Java+ssm+MySQL 基于SSM的游戏论坛设计与实现
     摘 要本论文主要论述了如何使用SSM框架开发一个游戏论坛,将严格按照软件开发流程进行各个阶段的工作,采用B/S架构JAVA技术,面向对象编程思想进行项目开发。在引言中,作者将论述游戏论坛的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个阶段分析设计......