SQL Lesson 4: 用JOINs进行多表联合查询

2023-10-24 03:10

本文主要是介绍SQL Lesson 4: 用JOINs进行多表联合查询,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

到目前为止我们已经学会了如何做一个单表的查询,但是在现实数据库中往往包含一组相关的数据表,这些表一般会符合数据库范式(normalization)[1]. 让我们先了解下关系数据库的范式

数据库范式(normalization)

数据库范式是数据表设计的规范,在范式规范下,数据库里每个表存储的重复数据降到最少(这有助于数据的一致性维护),同时在数据库范式下,表和表之间不再有很强的数据耦合,可以独立的增长 (ie. 比如汽车引擎的增长和汽车的增长是完全独立的). 范式带来了很多好处,但随着数据表的分离,意味着我们要查询多个数据属性时,需要更复杂的SQL语句,也就是本节开始介绍的多表连接技术。这样SQL的性能也会面临更多的挑战,特别是当大数据量的表很多的情况下.

如果一个实体(比如Dog)的属性数据被分散到多个数据表中,我们就需要学习如何通过 JOIN连表技术来整合这些数据并找到我们想要查询的数据项.

用JOINs进行多表联合查询

主键(primary key), 一般关系数据表中,都会有一个属性列设置为 主键(primary key)。主键是唯一标识一条数据的,不会重复复(想象你的身份证号码)。一个最常见的主键就是auto-incrementing integer(自增ID,每写入一行数据ID+1, 当然字符串,hash值等只要是每条数据是唯一的也可以设为主键.

借助主键(primary key)(当然其他唯一性的属性也可以),我们可以把两个表中具有相同 主键ID的数据连接起来(因为一个ID可以简要的识别一条数据,所以连接之后还是表达的同一条数据)(你可以想象一个左右连线游戏)。具体我们用到 JOIN 关键字。我们先来学习 INNER JOIN.

用INNER JOIN 连接表的语法
SELECT column, another_table_column, …
FROM mytable (主表)
INNER JOIN another_table (要连接的表)ON mytable.id = another_table.id (想象一下刚才讲的主键连接,两个相同的连成1条)
WHERE condition(s)
ORDER BY column, … ASC/DESC
LIMIT num_limit OFFSET num_offset;

通过ON条件描述的关联关系;INNER JOIN 先将两个表数据连接到一起. 两个表中如果通过ID互相找不到的数据将会舍弃。此时,你可以将连表后的数据看作两个表的合并,SQL中的其他语句会在这个合并基础上 继续执行(想一下和之前的单表操作就一样了).
还有一个理解INNER JOIN的方式,就是把 INNER JOIN 想成两个集合的交集。 

小贴士

INNER JOIN 可以简写做 JOIN. 两者是相同的意思,但我们还是会继续写作 INNER JOIN 以便和后面的 LEFT JOIN, RIGHT JOIN等相比较.

练习

还会用到之前的Movies表,但我们给数据库加了一张表 BoxOffice 存储着市场相关的信息,比如 收视率和销售数量等,这张表里有一个字段Movie_id 和Movies表的 Id是1-对-1的关系. 尝试下用 INNER JOIN 来解决下面的问题吧!.

Table: Movies (Read-Only)

IdTitleDirectorYearLength_minutes
1Toy StoryJohn Lasseter199581
2A Bug's LifeJohn Lasseter199895
3Toy Story 2John Lasseter199993
4Monsters, Inc.Pete Docter200192
5Finding NemoFinding Nemo2003107
6The IncrediblesBrad Bird2004116
7CarsJohn Lasseter2006117
8RatatouilleBrad Bird2007115
9WALL-EAndrew Stanton2008104
10UpPete Docter2009101
11Toy Story 3Lee Unkrich2010103
12Cars 2John Lasseter2011120
13BraveBrenda Chapman2012102
14Monsters UniversityDan Scanlon2013110

Table: Boxoffice (Read-Only)

Movie_idRatingDomestic_salesInternational_sales
58.2380843261555900000
147.4268492764475066843
88206445654417277164
126.4191452396368400000
37.9245852179239163000
68261441092370001000
98.5223808164297503696
118.4415004880648167031
18.3191796233170162503
77.2244082982217900167
108.3293004164438338580
48.1289916256272900000
27.2162798565200600000
137.2237283207301700000

Table(表): Movies

IdTitleDirectorYearLength_minutesMovie_idRatingDomestic_salesInternational_sales
1Toy StoryJohn Lasseter19958118.3191796233170162503
2A Bug's LifeJohn Lasseter19989527.2162798565200600000
3Toy Story 2John Lasseter19999337.9245852179239163000
4Monsters, Inc.Pete Docter20019248.1289916256272900000
5Finding NemoFinding Nemo200310758.2380843261555900000
6The IncrediblesBrad Bird200411668261441092370001000
7CarsJohn Lasseter200611777.2244082982217900167
8RatatouilleBrad Bird200711588206445654417277164
9WALL-EAndrew Stanton200810498.5223808164297503696
10UpPete Docter2009101108.3293004164438338580
11Toy Story 3Lee Unkrich2010103118.4415004880648167031
12Cars 2John Lasseter2011120126.4191452396368400000
13BraveBrenda Chapman2012102137.2237283207301700000
14Monsters UniversityDan Scanlon2013110147.4268492764475066843

练习 do it — 请完成如下任务

1.找到所有电影的线下Domestic_sales和线上销售额 

SELECT * FROM movies
inner join Boxoffice
on  Movies.id=Boxoffice.Movie_id

2.找到所有线上销售额比线下销售大的电影

 SELECT * FROM movies
inner join Boxoffice
on  Movies.id=Boxoffice.Movie_id
where International_sales > Domestic_sales

3.找出所有电影按市场占有率rating倒序排列 

SELECT * FROM movies
inner join Boxoffice
on  Movies.id=Boxoffice.Movie_id
order by Rating desc    

4.每部电影按线上销售额比较,排名最靠前的导演是谁,线上销量多少 

SELECT Director,International_sales  FROM movies
inner join Boxoffice
on  Movies.id=Boxoffice.Movie_id
order by International_sales desc
limit 1

 外连接(OUTER JOINs)

INNER JOIN 只会保留两个表都存在的数据(还记得之前的交集吗),这看起来意味着一些数据的丢失,在某些场景下会有问题.

真实世界中两个表存在差异很正常,所以我们需要更多的连表方式,也就是本节要介绍的左连接LEFT JOIN,右连接RIGHT JOIN 和 全连接FULL JOIN. 这几个 连接方式都会保留不能匹配的行。

用LEFT/RIGHT/FULL JOINs 做多表查询
SELECT column, another_column, …
FROM mytable
INNER/LEFT/RIGHT/FULL JOIN another_tableON mytable.id = another_table.matching_id
WHERE condition(s)
ORDER BY column, … ASC/DESC
LIMIT num_limit OFFSET num_offset;

INNER JOIN 语法几乎是一样的. 我们看看这三个连接方法的工作原理:
在表A 连接 B, LEFT JOIN保留A的所有行,不管有没有能匹配上B.反过来,RIGHT JOIN则保留所有B里的行。最后FULL JOIN 不管有没有匹配上,同时保留A和B里的所有行

我们还是可以用集合的图示来描述:

LEFT JOIN

RIGHT JOIN
 

FULL JOIN
 

将两个表数据1-1连接,保留A或B的原有行,如果某一行在另一个表不存在,会用 NULL来填充结果数据。所有在用这三个JOIN时,你需要单独处理 NULL. 关于 NULL 下一节会做更详细的说明

小贴士

这些Join也可以写作 LEFT OUTER JOINRIGHT OUTER JOIN, 或 FULL OUTER JOIN, 和 LEFT JOINRIGHT JOIN, and FULL JOIN 等价.

练习

我们会用两个新的表雇员表 Employees 和 办公室表 Buildings. 有一些办公室是新的,还没有雇员.

注意:因为我们这个练习DB的限制,只可以用 LEFT JOIN来解决问题.

Table: Employees (Read-Only)

RoleNameBuildingYears_employed
EngineerBecky A.1e4
EngineerDan B.1e2
EngineerSharon F.1e6
EngineerDan M.1e4
EngineerMalcom S.1e1
ArtistTylar S.2w2
ArtistSherman D.2w8
ArtistJakob J.2w6
ArtistLillia A.2w7
ArtistBrandon J.2w7
ManagerScott K.1e9
ManagerShirlee M.1e3
ManagerDaria O.2w6
EngineerYancy I.null0
ArtistOliver P.null0

Table: Buildings (Read-Only)

Building_nameCapacity
1e24
1w32
2e16
2w20

Table(表): Employees

RoleNameBuildingYears_employedBuilding_nameCapacity
EngineerBecky A.1e41e24
EngineerDan B.1e21e24
EngineerSharon F.1e61e24
EngineerDan M.1e41e24
EngineerMalcom S.1e11e24
ArtistTylar S.2w22w20
ArtistSherman D.2w82w20
ArtistJakob J.2w62w20
ArtistLillia A.2w72w20
ArtistBrandon J.2w72w20
ManagerScott K.1e91e24
ManagerShirlee M.1e31e24
ManagerDaria O.2w62w20
EngineerYancy I.null0nullnull
ArtistOliver P.null0nullnull

1.找到所有有雇员的办公室(buildings)名字

SELECT DISTINCT building FROM employees where building is not null

2.找到所有办公室和他们的最大容量

SELECT  Building_name,capacity FROM Buildings 

3.找到所有办公室里的所有角色(包含没有雇员的),并做唯一输出(DISTINCT)

SELECT  DISTINCT Employees.Role,Building_name from Buildings
LEFT JOIN Employees
on Buildings.Building_name=Employees.Building

4.找到所有有雇员的办公室(buildings)和对应的容量

SELECT  Building,Capacity FROM Employees left join  Buildings
on employees.Building=Buildings.Building_name
where Building is not null 

 

这篇关于SQL Lesson 4: 用JOINs进行多表联合查询的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

MySQL 日期时间格式化函数 DATE_FORMAT() 的使用示例详解

《MySQL日期时间格式化函数DATE_FORMAT()的使用示例详解》`DATE_FORMAT()`是MySQL中用于格式化日期时间的函数,本文详细介绍了其语法、格式化字符串的含义以及常见日期... 目录一、DATE_FORMAT()语法二、格式化字符串详解三、常见日期时间格式组合四、业务场景五、总结一、

mysql线上查询之前要性能调优的技巧及示例

《mysql线上查询之前要性能调优的技巧及示例》文章介绍了查询优化的几种方法,包括使用索引、避免不必要的列和行、有效的JOIN策略、子查询和派生表的优化、查询提示和优化器提示等,这些方法可以帮助提高数... 目录避免不必要的列和行使用有效的JOIN策略使用子查询和派生表时要小心使用查询提示和优化器提示其他常

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

MySQL InnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据

《MySQLInnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据》mysql的ibdata文件被误删、被恶意修改,没有从库和备份数据的情况下的数据恢复,不能保证数据库所有表数据... 参考:mysql Innodb表空间卸载、迁移、装载的使用方法注意!此方法只适用于innodb_fi

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespace id不一致处理

《mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespaceid不一致处理》文章描述了公司服务器断电后数据库故障的过程,作者通过查看错误日志、重新初始化数据目录、恢复备... 周末突然接到一位一年多没联系的妹妹打来电话,“刘哥,快来救救我”,我脑海瞬间冒出妙瓦底,电信火苲马扁.

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav

MySQL进阶之路索引失效的11种情况详析

《MySQL进阶之路索引失效的11种情况详析》:本文主要介绍MySQL查询优化中的11种常见情况,包括索引的使用和优化策略,通过这些策略,开发者可以显著提升查询性能,需要的朋友可以参考下... 目录前言图示1. 使用不等式操作符(!=, <, >)2. 使用 OR 连接多个条件3. 对索引字段进行计算操作4

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock