《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

相关文章

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

SQL server数据库如何下载和安装

《SQLserver数据库如何下载和安装》本文指导如何下载安装SQLServer2022评估版及SSMS工具,涵盖安装配置、连接字符串设置、C#连接数据库方法和安全注意事项,如混合验证、参数化查... 目录第一步:打开官网下载对应文件第二步:程序安装配置第三部:安装工具SQL Server Manageme

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅谈mysql的not exists走不走索引

《浅谈mysql的notexists走不走索引》在MySQL中,​NOTEXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引,下面就来介绍一下mysql的notexists走不走索... 在mysql中,​NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I