MySQL联合查询

内容引出

我们有一个博客网站,里面有:

  • 很多用户(user 表)

  • 很多文章(weibo 表)

  • 很多评论(comment 表)

我们希望能展示:

哪篇文章上,发了什么评论”。

1. user 表:用户信息表

字段名类型说明
idbigint主键
usernamevarchar(50)登录用户名
passwordvarchar(100)登录密码
nicknamevarchar(50)显示昵称
createdtimestamp注册时间

2. weibo 表:微博内容表

字段名类型说明
idbigint主键
contentvarchar(255)微博内容
createdtimestamp发布时间
user_idbigint发布用户ID

3. comment 表:评论信息表

字段名类型说明
idbigint主键
contentvarchar(255)评论内容
createdtimestamp评论时间
user_idbigint评论者用户ID
weibo_idbigint被评论微博ID

如果只看到了微博表就看不到用户根据某个微博发的评论了,如果只看评论表就看不到,某个被评论发布的微博的具体信息了

select* from weibo;

你只能看到每一条微博的内容、发布时间、发布者 ID,但你完全看不到这条微博有哪些评论、是谁评论的、评论了什么


select* from comment;

你可以看到评论者 ID、被评论微博的 ID,但你并不知道这个微博的内容是什么,也不知道用户昵称,只能看到 ID。


那我们究竟如何实现最初的目标  “哪篇文章上,发了什么评论”  呢?

如果你只是看“微博文章表”,你看不到微博的评论;
如果你只是看“评论表”,你看不到评论发布到那个微博的具体信息;

为了解决这个问题,我们需要把评论信息,微博信息还有用户信息联合在一起也就是把评论表、微博表、用户表的信息整合到一起,才能还原出业务全貌。

联合查询(Join Query)是关系型数据库中非常重要的一种查询方式。我们之所以需要联合查询,是因为数据库设计中存在“表与表之间的关联关系”,而联合查询就是为了获取多个表之间的关联数据。总之一句话,关联查询就是为了从多个表中获取信息合并在一起用。

多表联合查询时MYSQL内部是如何进⾏计算的


参与查询的所有表(user,weibo,comment)取笛卡尔积,结果集在临时表中

这将会是一个十分庞大的内容,所以业务中我们会尽量避免笛卡尔积。

观察哪些记录是有效数据,根据三个表的关联关系过滤掉⽆效数据

找到微博表中的id 然后再在评论表中找到weibo_id 如果这条评论的weibo_id和微博表中的id相同说明这条评论确实就是发布在相关的微博上面的。通过这个条件我们可以确定微博表和评论表的关系

如何确定是谁发布评论的呢?

道理相同,只需要在用户表中找到id,然后在评论表中找到user_id,如果相同,可以确定这条评论确实是相关用户发布的。

从上面分析可以推导出,3个表关联只需要2个连接条件,那么n个表关联就需要n-1个连接条件。


注意:

上面表的设计严格遵从了数据库范式所以我们可以利用关联查询来进行查询

因为在数据设计时由于范式的要求数据被拆分到多个表中,那么要查询⼀个条数据的完整信息,就要从多个表中获取数据。

内连接

语法

select 字段 from 表1 别名1, 表2 别名2

where 连接条件 and 其他条件;

这里的连接条件遵从上面我们推导出来的连接条件的规律。


语法糖形式:

select 字段 from 表1 别名1

[inner] join 表2 别名2 on 连接条件

where 其他条件;

在这里的join 表 别名  on 连接条件

同样遵从连接条件的规律可以这样写:

select 字段 from 表1 别名1

[inner] join 表2 别名2 on 连接条件,

[inner] join 表3 别名3 on 连接条件,

.

.

.

[inner] join 表n 别名n on 连接条件

where 其他条件;


示例

示例 1:

查询所有评论的详细信息(评论者昵称 + 评论内容 + 微博内容)

select u.nickname,c.content,w.content
from comment c
join weibo w on c.weibo_id = w.id
join user u on c.user_id = u.id
order by c.created DESC;;
示例 2:

查询某条微博的所有评论(比如 weibo_id = 201)

select w.content , c.content
from weibo w
join comment c on c.weibo_id = w.id
where c.weibo_id = 201
order by c.created ASC;;

外连接

外连接(Outer Join)用于查询两个表中不完全匹配的数据
它不仅返回匹配成功的行,还会保留一边表中没有匹配成功的行,未匹配的数据列补 NULL

  • 外连接分为左外连接、右外连接和全外连接三种类型,MySQL不⽀持全外连接。
  • 左外连接:返回左表的所有记录和右表中匹配的记录。如果右表中没有匹配的记录,则结果集中对应字段会显⽰为NULL。
  • 右外连接:与左外连接相反,返回右表的所有记录和左表中匹配的记录。如果左表中没有匹配的记录,则结果集中对应字段会显⽰为NULL。
  • 全外连接:结合了左外连接和右外连接的特点,返回左右表中的所有记录。如果某⼀边表中没有匹

配的记录,则结果集中对应字段会显⽰为NULL。


左外连接

左外连接:以JOIN左侧表作为驱动表,将该表记录都查询出来,不满足连接条件时,来自右侧表的中的字段补NULL。

听起来很抽象,我们举一个小例子

比如某电商平台,有商品表和商品厂家表,在列举商品时希望把后缀的厂家信息也都列出来,

某电商平台有两个表:

  • product:商品表

  • manufacturer:厂商信息表

正常情况下,每一件商品都有一个厂商:

商品名价格厂商 ID
小米手机3001
小米手表2001
华为电视6002

厂商表:

厂商 ID厂商名
1小米
2

华为

有一些“山寨货”也偷偷上线了,比如:

菠萝手机,大米手表,鸭蛋电视

商品名价格厂商 ID
小米手机3001
小米手表2001
华为电视6002
菠萝手机100null
大米手表30       null
鸭蛋电视200null

这些商品没有合法厂商信息,manufacturer_idNULL,或者压根在 manufacturer 表中找不到对应记录。这个时候我们该怎么查商品+厂商信息?使用 LEFT JOIN左连接

SELECT
p.name ,p.price ,m.name
FROM product p
LEFT JOIN manufacturer m ON p.manufacturer_id = m.id;

 查询结果

商品名价格厂商名
小米手机300小米
小米手表200小米
华为电视600华为
菠萝手机100NULL
大米手表30NULL
鸭蛋电视200NULL

 左连接(LEFT JOIN)就是“左边全保留,右边没匹配就补 NULL”;右连接反之。


右外连接

右外连接:以JOIN右侧表作为驱动表,将该表记录都查询出来,不满足连接条件时,来自左侧表的中的字段补NULL

如果你想保留的是右边的表,哪怕左边没对应数据,也要显示——那就要用 右外连接(RIGHT JOIN)。我们仍然使用商品,厂商的小案例来帮助理解。

前面我们讲了 LEFT JOIN(左外连接) 的例子:保留所有商品,哪怕没匹配的厂商信息,也要显示。

那 RIGHT JOIN 呢?它是反过来 —— 保留所有厂商,哪怕该厂商还没有生产任何商品,也要显示。

商品表如下

商品名价格厂商 ID
小米手机3001
小米电视4001
华为手机3002
菠萝手机250NULL

厂商表 

厂商 ID厂商名
1小米
2华为
3苹果
4谷歌

 苹果和谷歌厂商虽然注册了厂商ID但是并没有在商品表中出现任何商品,这个时候我们想展示所有商品对应的厂商时,我们想看到的应该是所有厂商的商品情况,哪怕还没有商品!

所以反过来使用右外连接

SELECT
p.name ,p.price AS 价格,m.name 
FROM product p
RIGHT JOIN manufacturer m ON p.manufacturer_id = m.id;

查询结果

商品名价格厂商名
小米手机300小米
小米电视400小米
华为手机300华为
NULLNULL小米
NULLNULL谷歌

RIGHT JOIN 是 “右边优先” 的外连接,它让你可以查出“右表中存在但左表中没有匹配”的数据

全外连接

综合左外连接和右外连接,我们直接总结出全外连接(FULL OUTER JOIN)就是左外连接和右外连接的查询结合

小米手机300小米
小米手表200小米
华为电视600华为
菠萝手机100NULL
大米手表30NULL
鸭蛋电视200NULL
NULLNULL小米
NULLNULL谷歌
-- 注意:MySQL 本身不直接支持 FULL OUTER JOIN,但可以这样模拟:
SELECT ... FROM A
LEFT JOIN B ON ...
UNION
SELECT ... FROM A
RIGHT JOIN B ON ...

全外连接 = 左外连接 + 右外连接的并集,就是从两个方向都“不漏数据”。 


⾃连接

自连接就是一张表和自己做连接查询
本质上就是对一张表进行笛卡尔积运算并加以条件筛选,让“同一个表中的两行”可以彼此比较或建立关系。

自连接的作用

  • 实现 行与行的比较

  • 查询 同一表中的父子关系、上下级关系

  • 构建 树形结构

  • 行变成列(需要配合聚合函数)

应用场景
电商中的分类树,就是用自连接设计

  • 生活用品
  • 家用电器
  • 电脑
    • 电脑整机
      • 笔记本
      • 台式机
      • 游戏本
      • 一体机
      • 平板电脑
    • 电脑配件
    • 游戏设备
  • 手机

一家公司的员工组织结构,都是员工,但是员工又存在上下级关系。

idnameparent_id
1生活用品NULL
2家用电器NULL
3电脑NULL
4笔记本3
5台式机3
6一体机3
7平板电脑3
8游戏本4
9手机NULL

你会发现:

  • 所有分类都在同一张表里

  • 某些分类的 parent_id 指向其他分类的 id 这就是自连接的典型场景

SELECT
  c1.name AS 分类名,
  c2.name AS 上级分类
FROM category c1
LEFT JOIN category c2 ON c1.parent_id = c2.id;

查询结果 

分类名上级分类
电脑NULL
生活用品NULL
家用电器NULL
手机NULL
笔记本电脑
游戏本笔记本
台式机电脑

自连接是实现同表数据之间相互比较、层级关系、树结构查询的强大工具,它让我们能用一张表表达出“行与行之间的逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值