《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数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

mysql8.0.43使用InnoDB Cluster配置主从复制

《mysql8.0.43使用InnoDBCluster配置主从复制》本文主要介绍了mysql8.0.43使用InnoDBCluster配置主从复制,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录1、配置Hosts解析(所有服务器都要执行)2、安装mysql shell(所有服务器都要执行)3、

k8s中实现mysql主备过程详解

《k8s中实现mysql主备过程详解》文章讲解了在K8s中使用StatefulSet部署MySQL主备架构,包含NFS安装、storageClass配置、MySQL部署及同步检查步骤,确保主备数据一致... 目录一、k8s中实现mysql主备1.1 环境信息1.2 部署nfs-provisioner1.2.

idea+spring boot创建项目的搭建全过程

《idea+springboot创建项目的搭建全过程》SpringBoot是Spring社区发布的一个开源项目,旨在帮助开发者快速并且更简单的构建项目,:本文主要介绍idea+springb... 目录一.idea四种搭建方式1.Javaidea命名规范2JavaWebTomcat的安装一.明确tomcat

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR