《SQL必知必会——第12、13课:联结表、创建高级联结》

2024-08-28 13:58

本文主要是介绍《SQL必知必会——第12、13课:联结表、创建高级联结》,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       两个多月没有更新博客,有时不禁问时间都去哪儿了。似乎每个周末也没有打游戏、也没有追剧消磨时光,心里倒想着过得这么休闲、悠哉,但现实却是各种压力山大,还需继续奋斗。有点跑题了,还是说说这两课要讲的内容吧。这两课的内容说简单也简单,说复杂也复杂。简单是因为,这两课讲的内容其实就是查询操作,虽说有一些新花样,但万变不离其宗。说复杂呢,因为这次查询涉及的表数量都超过2个,也就是不在一张表上折腾了,而是同时在多张表上折腾。

       第12课 联结表

       “sql最强大的功能之一就是能在数据查询的执行中联结(join)表,联结是利用sql的select能执行的最重要的操作”。这样的表述在本书中还是很少见的,连续用了两个最字,可见联结的重要。那什么是联结呢?联结就是join,把多个表联到一起,原来select * from A,现在是select * from A,B,C,也就是同时查A表、B表、C表,如果这些表都不相干,风马牛不相及的几张表也可以放在一起查?对,都可以放在一起查,只要你认为有意义,符合你的期望,你都可以放到一起查。对于联结,千万别再字眼上较劲,理解就好。那为什么需要联结呢?因为数据库是关系型的,表是关系型的。我们在设计数据库时,相同的数据不会放在很多表中,因为这样会产生大量无意义数据,非常占地方,也不好操作。比如学生成绩表,没必要保存学生的出生年月、家庭地址等,这些信息会保存在学生基本信息表中,但是会在学生成绩表中保存学生基本信息id。这两张表通过学生基本信息id相互关联,这就是关系表,根据业务场景,将要保存的信息分解成多个表,一类数据一个表,各表通过某些共同的值相互关联,这样做的好处,显而易见是信息不会重复保存,数据一致性更好,可伸缩性也更好。下面是联结查询示例:

select vend_name, prod_name, prod_price from vendors, products where vendors.vend_id = products.vend_id;

       和以往的查询不同,这条查询from子句后面列出了两个表:vendors和products,而where子句后面查询条件是两个表中的共有字段vend_id,具体执行时,也就是联结两个表查询时,实际就是将第一个表中的每一行与第二个表中的每一行配对,where子句作为过滤条件,只包含那些匹配给定条件的行。如果没有where条件,那么可想而知,第一个表中的每一行将于第二个表中的每一行配对输出,查询结果的行数将是第一个表中的行数乘以第二个表中的行数。其结果就是笛卡尔积:假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为:{ (a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2) }。所以前面说,其实就算两个不相干的表也可以放在一起联结查询,无非结果是笛卡尔积,只要业务上能接受就行,不过,大部分业务应该不会这么干。所以要保证所有的联结都有where子句。

       联结也分很多类型,上面的示例,其实准确讲属于等值联结,它基于两个表之间的相等测试,这种联结也称为内联结。下面是上面示例的另一种写法:

select vend_name, prod_name, prod_price from vendors inner join products on vendors.vend_id = products.vend_id;

       两者查询结果一样,语句表述不一样。第一种可以称为简单语法,第二种可以称为标准语法。实际工作中用哪种,完全看个人喜好了,没有标准答案。

       下面是联结三个表的示例:

select prod_name, vend_name, prod_price, quantity 
from order_items, products, vendors 
where products.vend_id = vendors.vend_id 
and order_items.prod_id = products.prod_id
and order_num = 20007;

       这里的from子句列出三个表,where子句定义的第3个联结条件用来过滤订单20007中的物品(这条示例语句也可以用子查询来写,但需要考量性能,哪种性能好用哪种)。说白了就是将一份长的信息,合理拆解后分别保存进不同表中,查询时,通过关联字段和过滤条件,再把数据查出来。其实这里难的不是编写sql语句,而是拆解信息,需要非常熟悉业务,才能将业务数据进行合理的组织、划分,数据组织的高效,后面的业务逻辑处理也会省力很多。当然,业务数据也允许一定的冗余,因为拆分的太细,查询时势必要联结很多表,联结的表越多,性能下降越厉害,说白了就是空间换时间。

       第13课 创建高级联结

       因为使用联结,sql语句一般都很长,为了缩短sql语句,可以给表使用别名,像前面给列和计算字段使用别名一样。比如:

select cust_name, cust_contact 
from customers as c, orders as o, order_items as oi 
where c.cust_id = o.cust_id 
and oi.order_num = o.order_num
and prod_id= 'RGAN01';

       语句里面的c、o、oi就是表别名,用了别名可以缩短sql语句长度,不过不用也行,看个人喜好吧。

       使用不同类型的联结,根据业务需求,除了前面比较常见的内联接,实际还会有:自联结、自然联结、外联结

       自联结

       顾名思义,就是自己和自己联结,如下例所示:

select c1.cust_id, c1.cust_name, c1.cust_contact
from customers as c1, customers as c2
where c1.cust_name = c2.cust_name
and c2.cust_contact = 'Jim Jones'

       查询中需要的两个表实际上是相同的表,where首先联结两个表,然后按第二个表中的cust_contact过滤数据,返回所需的数据。很多场景下,可以用自联结,也可以用子查询实现,一般子查询更容易理解,但自联结性能更好。

       自然联结

       感觉没啥讲的,因为前面提到的内联结都是自然联结。自然联结就是排除返回结果中一个列多次出现, 使得每个列只返回一次。然后查询时对一个表使用通配符,而对其他表的列使用明确的子集来完成。但工作中都会控制返回的列,所以基本不会出现一个列多次出现,这种写法也就基本不会用。但知道点总是好的。

select c.*, o.order_num, oi.prod_id
from customers as c, orders as o, order_item as oi
where c.cust_id = o.cust_id
and o.order_num = oi.order_num
and oi.prod_id = 'RGAN01'

       外联结

       内联接是将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。示例如下:

select customers.cust_id, orders.order_num 
from customers left outer join orders 
on customers.cust_id = orders.cust_id;

       这条语句执行时, cust_id没有order_num的也会被返回。在使用outer join语法时,必须使用right或left关键字指定包括其所有行的表。right指出的是outer join右边的表,而left指出的是outer join左边的表。这是什么意思呢?前面说联结在执行时就是将第一个表中的每一行与第二个表中的每一行配对。由于外联结没有关联的行也会被输出,那么在执行时就需要指定一个表作为基准表,从基准表中取出每一行,然后在另一个表中查询符合条件的行,配对输出,如果没有匹配到,则输出null,显然left或right作用就是指定基准表。但其实无非就是表的顺序,哪个表放在outer join前面、哪个表放在outer join后面,然后可以发现通过调整表的顺序,其实left或者right只用其中一个就可以了,左就是右,右就是左。

       使用带聚集函数的联结

       其实既然已经联结,所以不管操作几个表,你都看做是操作一个大表,那么聚集函数自然可以应用到联结查询。如下例所示:

select customers.cust_id, count(orders.order_num) as num_ord 
from customers inner join orders 
on customers.cust_id = orders.cust_id
group by customers.cust_id;

       联结,也就是常说的多表查询,没啥难的,如果感觉难,那就先混个脸熟,隔几天再看,多看几次,慢慢也就理解了。

这篇关于《SQL必知必会——第12、13课:联结表、创建高级联结》的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1114959

相关文章

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

MySQL中On duplicate key update的实现示例

《MySQL中Onduplicatekeyupdate的实现示例》ONDUPLICATEKEYUPDATE是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突,则会执行更新操作,而不是抛... 目录1/ ON DUPLICATE KEY UPDATE的简介2/ ON DUPLICATE KEY UP

MySQL分库分表的实践示例

《MySQL分库分表的实践示例》MySQL分库分表适用于数据量大或并发压力高的场景,核心技术包括水平/垂直分片和分库,需应对分布式事务、跨库查询等挑战,通过中间件和解决方案实现,最佳实践为合理策略、备... 目录一、分库分表的触发条件1.1 数据量阈值1.2 并发压力二、分库分表的核心技术模块2.1 水平分

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手