当前位置: 首页 > news >正文

MSQL系列(十三) Mysql实战-left/right/inner join 使用详解及索引优化

Mysql实战-left/right/inner join 使用详解及索引优化

前面我们讲解了B+Tree的索引结构,也详细讲解下Join的底层驱动表 选择原理,今天我们来了解一下为什么会出现内连接外连接,两种连接方式,另外实战一下内连接和几种最常用的join语法

  • Left join 左表 left join 右表查询
  • right join 左表 right join 右边查询
  • inner join 两个表 inner join查询

文章目录

      • Mysql实战-left/right/inner join 使用详解及索引优化
        • 1.建表及测试数据
        • 2.为什么会有内连接和外连接
        • 2.外连接的连接条件和where条件有什么区别
        • 3.左连接 left join
        • 4.右连接 right join
        • 5.内连接 inner join

1.建表及测试数据

我们先创建两个表 test_user 和 test_order 这两个表作为我们的测试表及测试数据

  • test_user 5条数据, 索引只有主键id
  • test_order 5条数据,索引同样也只有主键id
#创建test_user
CREATE TABLE `test_user` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',`user_name` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名字',`age` int DEFAULT NULL COMMENT '年龄',PRIMARY KEY (`id`),KEY `idx_age` (`age`),KEY `idx_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';#创建表 test_order
CREATE TABLE `test_order` (`id` int NOT NULL AUTO_INCREMENT,`user_id` int NOT NULL COMMENT '用户id,就是test_user的唯一主键id',`order_name` varchar(32) NOT NULL DEFAULT '订单信息',`pay` int NOT NULL DEFAULT '0',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表';

插入数据

#插入 user 用户数据
INSERT INTO `test`.`test_user` (`id`, `id_card`, `user_name`, `age`) VALUES (1, '11', 'aa', 10);
INSERT INTO `test`.`test_user` (`id`, `id_card`, `user_name`, `age`) VALUES (2, '22', 'bb', 20);
INSERT INTO `test`.`test_user` (`id`, `id_card`, `user_name`, `age`) VALUES (3, '33', 'cc', 30);
INSERT INTO `test`.`test_user` (`id`, `id_card`, `user_name`, `age`) VALUES (4, '44', 'dd', 40);#插入 order 订单数据
INSERT INTO `test`.`test_order` (`id`, `order_name`, `user_name`, `pay`) VALUES (1, '衣服', 'aa', 100);
INSERT INTO `test`.`test_order` (`id`, `order_name`, `user_name`, `pay`) VALUES (2, '鞋子', 'bb', 200);
INSERT INTO `test`.`test_order` (`id`, `order_name`, `user_name`, `pay`) VALUES (3, '电视', 'bb', 300);

看两个表的关系, 可以知道

  • user用户表有4个用户, aa,bb,cc,dd
  • order订单表有 1,2,3 个订单, aa一条衣服, bb用户一个鞋子,一个电视

在这里插入图片描述

2.为什么会有内连接和外连接

下面我们来看下下面的场景

  • 我们要查询 每个人买了什么东西, 花了多少钱 ?
  • 我们的 两个表的连接条件就是 test_user.id = test_order.user_id
select test_user.id, test_user.user_name, test_order.order_name, test_order.pay from test_user, test_order where test_user.id = test_order.user_id;

执行结果
在这里插入图片描述

根据查询结果,我们可以很明确的知道

  • 1.aa的用户,买了衣服,花了100
  • 2.bb的用户,买了鞋子花了200,买了电视花了300
  • 3.我们查询不出来 cc 和 dd同学, 因为他们俩没买东西

但是如果是 我们要知道每一个人的消费情况, 即使没买东西的人也要展示出来,该如何处理?

对于上面的test_user和test_order,我们的需求就是 对于每一个同学,我都要知道他们的花费情况, 哪怕你没有买任何一个东西,我也要知道结果

这个问题的本质就是 如果驱动表中的记录,没有在被驱动表中查询到匹配的记录,也要返回结果,呈现出来

  • 内连接
    • 内连接的两个表,如果驱动表中的记录,在被驱动表中找不到匹配的记录,该记录不会加入到最后的结果集
    • 我们上边用的where test_user.id = test_order.user_id ,这种连接方式就是内连接
    • 未匹配的记录不会出现在结果中
  • 外连接
    • 外连接的两个表,如果驱动表的记录, 在被驱动表中没有匹配的记录,仍然要加入到结果集
    • 未匹配的记录,都要加入结果集
    • 左外连接 left join 语法
    • 右外连接 right join语法
2.外连接的连接条件和where条件有什么区别

上面我们已经知道了 外连接就是 不匹配的记录也要返回结果

这个就会带来一个问题, 比如我的驱动表有100条记录,但是我的外连接 我不想让驱动表全部数据加入到结果集, 但是外连接的本质就是不匹配的就展示到结果集,这种情况该如何处理 ?

这就是 on 连接条件中的过滤条件 和 where 子句中的过滤条件的区别,我们可以通过 on连接条件的过滤条件和 where子句的过滤条件进行区分,解决上面的问题

  • where子句的过滤条件
    • where子句的过滤条件就是不论内连接,外连接,不符合where子句的,全部都不会被加入到最终结果集
  • on连接条件的过滤条件
    • 对于内连接来说 on连接条件的过滤条件和where子句的过滤条件一样对待,没有任何区别,二者是等价的
    • 对于外连接来捉 on连接条件的过滤条件,如果在被驱动表中无法匹配on的过滤条件,该记录是要加入到结果集中
    • 不符合匹配条件的被驱动表的数据,全部用NULL值填充
3.左连接 left join

下面我们来看下左外连接, 简称左连接 left join, 还是上面的两个表和数据,执行左连接

先纠正一个误区
!!! 左连接并不是说 左边的数据不动,右边匹配的拼上来
!!! 左连接并不是说 左边的数据不动,右边匹配的拼上来
!!! 左连接并不是说 左边的数据不动,右边匹配的拼上来

要按照错误的这个说法,下面的语句执行完 左边不动,还是4条,1,2,3,4 但是明显不是

左连接真正意义是 左边驱动表在右侧匹配找到,就拼数据,不匹配拼NULL

select * from test_user left  join test_order on test_user.id = test_order.user_id ;
explain select * from test_user left  join test_order on test_user.id = test_order.user_id ;

执行结果
在这里插入图片描述
在这里插入图片描述

前面我们已经分析过 left join 哪个是驱动表,哪个是非驱动表, 从结果来看 test_user就是驱动表

  • test_user用户表是 驱动表
  • test_order 是被驱动表
  • user表 有数据, id=1,2,3,4
  • order表有 user_id 的数据, 1,2,2
  • on 连接条件 id相同,test_user.id = test_order.user_id
  • 查询结果 数据变成了5条数据
  • 因为被驱动表 找到了2条 user_id = 2的 bb用户买了两次东西, 所以要展示2次, 变成了 1,2,2,3,4 五条数据
  • 购买了东西的 1-aa, 2-bb 用户查询出来了
  • 没有购买东西的 3-cc,4-dd 用户也查询出来了,只不过结果用NULL填充
4.右连接 right join

下面我们来看下右外连接, 简称右连接 right join, 还是上面的两个表和数据,执行右连接

select * from test_user right  join test_order on test_user.id = test_order.user_id ;
explain select * from test_user right  join test_order on test_user.id = test_order.user_id ;

可以知道 test_order是驱动表,要在 test_user中找 和他匹配的数据
执行结果
在这里插入图片描述

  • test_order是驱动表
  • test_user是被驱动表
  • test_order 有 1,2,2 三条数据
  • 匹配出来 全都在 被驱动表 user中存在
  • 所以救国就是 1,2,2

现在我们插入一条 不在 user的数据, user_id = 5, user中没有5的这个数据,只有id=1/2/3/4, 再执行右连接查询,看下结果

INSERT INTO `test`.`test_order` (`id`, `user_id`, `order_name`, `pay`) VALUES (4, 5, 'xxx',  400);
select * from test_user right  join test_order on test_user.id = test_order.user_id ;

在这里插入图片描述
执行结果 可以明确看到, test_order.user_id =5这一条数据, 在被驱动表 test_user 中不存在id=5的数据, 所以 就用Null填充

5.内连接 inner join

最开始我们举例子 用的下面的例子 ,虽然没有明确 声明 inner join,但是本质就是内连接

select * from test_user, test_order where test_user.id = test_order.user_id;

在这里插入图片描述
上面的这种方式 和 下面2中本质一致, inner 关键字可以省略

select * from test_user join test_order  where test_user.id = test_order.user_id;
select * from test_user inner join test_order where test_user.id = test_order.user_id;
#等价于
select * from test_user, test_order where test_user.id = test_order.user_id;

至此,我们已经彻底知道了 left join, right join ,inner join的区别和联系,这对于我们实际项目中SQL语句有至关重要的作用,一定要牢记于心

相关文章:

MSQL系列(十三) Mysql实战-left/right/inner join 使用详解及索引优化

Mysql实战-left/right/inner join 使用详解及索引优化 前面我们讲解了BTree的索引结构,也详细讲解下Join的底层驱动表 选择原理,今天我们来了解一下为什么会出现内连接外连接,两种连接方式,另外实战一下内连接和几种最常用的join…...

前端面试题之HTML篇

1、src 和 href 的区别 具有src的标签有:script、img、iframe 具有href的标签有:link、a 区别 src 是source的缩写。表示源的意思,指向资源的地址并下载应用到文档中。会阻塞文档的渲染,也就是为什么js脚本放在底部而不是头部的…...

Django ORM:数据库操作的Python化艺术

Django的对象关系映射器(ORM)是其核心功能之一,允许开发者使用Python代码来定义、操作和查询数据库。这篇文章将带你深入了解Django ORM的强大之处,从基本概念到高级查询技巧,提供丰富的示例帮助你掌握使用Django ORM进…...

react受控组件与非受控组件

React中的组件可以分为受控组件和非受控组件: 受控组件:受控组件是指组件的值受到React组件状态的控制。通常在组件中,我们会通过state来存储组件的值,然后再将state的值传递给组件的props,从而实现组件的双向数据绑定…...

小米产品面试题:淘宝为何需要确认收货?京东为何不需要?

亲爱的小米粉丝们,大家好!我是小米,一个热爱技术、热衷于分享的小编。今天,我要和大家聊聊一个有趣的话题:为什么淘宝购物需要确认收货,而京东不需要?这可是一个让很多人纳闷的问题,…...

(1)上位机底部栏 UI如何设置

上位机如果像设置个多页面切换: 位置: 代码如下: "tabBar": {"color": "black","selectedColor": "#d43c33","borderStyle":"black","backgroundColor": …...

中国多主数据库:压强投入,期待破茧

拿破仑曾说:“战争的艺术就是在某一点上集中最大优势兵力”,强调了力量集中的重要性。 如今,国际形势风云变幻,西方世界对中国的围剿不再仅仅体现在军事和地缘政治上,而更多表现在经济与科技上。在科技领域&#xff0…...

JavaScript在ES6及后续新增的常用新特性

JavaScript经历了不同标本的迭代,在不断完善中会添加不同的新特性来解决前一个阶段的瑕疵,让我们开发更加便捷与写法更加简洁! 1、箭头函数: 箭头函数相比传统的函数语法,具有更简洁的语法、没有自己的this值、不会绑…...

试试流量回放,不用人工写自动化测试case了

大家好,我是洋子,接触过接口自动化测试的同学都知道,我们一般要基于某种自动化测试框架,编写自动化case,编写自动化case的依据来源于接口文档,对照接口文档里面的请求参数进行人工添加接口自动化case 其实…...

密钥管理系统功能及作用简介 安当加密

密钥管理系统的功能主要包括密钥生成、密钥注入、密钥备份、密钥恢复、密钥更新、密钥导出和服务,以及密钥的销毁等。 密钥生成:通过输入一到多组的密钥种子,按照可再现或不可再现的模式生成所需要的密钥。一般采用不可再现模式作为密钥生成…...

vue中watch属性的用法

在Vue中,watch属性用于监听一个数据的变化,并且在数据变化时执行一些操作。它可以观察一个具体的数据对象,从而在该数据对象发生变化时触发对应的回调函数。 使用watch属性的步骤如下: 在Vue实例中添加一个watch对象 new Vue({…...

Redis-使用java代码操作Redis

🏅我是默,一个在CSDN分享笔记的博主。📚📚 ​ 🌟在这里,我要推荐给大家我的专栏《Linux》。🎯🎯 🚀无论你是编程小白,还是有一定基础的程序员,这…...

0基础学习PyFlink——事件时间和运行时间的窗口

大纲 定制策略运行策略Reduce完整代码滑动窗口案例参考资料 在 《0基础学习PyFlink——时间滚动窗口(Tumbling Time Windows)》一文中,我们使用的是运行时间(Tumbling ProcessingTimeWindows)作为窗口的参考时间: reducedkeyed.window(TumblingProcess…...

Git Rebase 优化项目历史

在软件开发过程中,版本控制是必不可少的一环。Git作为当前最流行的版本控制系统,为开发者提供了强大的工具来管理和维护代码历史。git rebase是其中一个高级特性,它可以用来重新整理提交历史,使之更加清晰和线性。本文将详细介绍g…...

两种MySQL OCP认证应该如何选?

很多同学都找姚远老师说要参加MySQL OCP认证培训,但绝大部分同学并不知道MySQL OCP认证有两种,以MySQL 8.0为例。 一种是管理方向,叫:Oracle Certified Professional, MySQL 8.0 Database Administrator(我考试的比较…...

Java用log4j写日志

日志可以方便追踪和调试问题,以前用log4net写日志,换Java了改用log4j写日志,用法和log4net差不多。 到apache包下载下载log4j的包,解压后把下图两个jar包引入工程 先到网站根下加一个log4j2.xml的配置文件来配置日志的格式和参…...

PCTA认证考试-01_TiDB数据库架构概述

TiDB 数据库架构概述 一、学习目标 理解 TiDB 数据库整体结构。了解 TiDB Server,TiKV,TiFlash 和 PD 的主要功能。 二、TiDB 体系架构 1. TiDB Server 2. TiKV OLTP 3. Placement Driver 4. TiFlash OLAP OLTPOLAPHTAP...

路由过滤路由引入

目录 一、实验拓扑 二、实验需求 三、实验步骤 1、配置IP地址 2、配置RIP和OSPF 3、配置路由引入 4、使用路由过滤,使 R4 无法学到 R1 的业务网段路由,要求使用 prefix-list 进行匹配 5、OSPF 区域中不能出现 RIP 协议报文 一、实验拓扑 二、实…...

视频剪辑技巧:批量合并视频,高效省时,添加背景音乐提升品质

随着社交媒体的兴起,视频制作越来越受到人们的关注。掌握一些视频剪辑技巧,可以让我们轻松地制作出令人惊艳的视频。本文将介绍一种高效、省时的视频剪辑技巧,帮助您批量合并视频、添加背景音乐,并提升视频品质。现在一起来看看云…...

数据可视化篇——pyecharts模块

在之前的文章中我们已经介绍过爬虫采集到的数据用途之一就是用作可视化报表,而pyecharts作为Python中可视化工具的一大神器必然就受到广大程序员的喜爱。 一、什么是Echarts? ECharts 官方网站 : https://echarts.apache.org/zh/index.html ECharts 是…...

Python--快速入门二

Python--快速入门二 1.Python数据类型 1.可以通过索引获取字符串中特定位置的字符: a "Hello" print(a[3]) 2.len函数获取字符串的长度: a "Hello" print(a) print(len(a)) 3.空值类型表示完全没有值: 若不确定当…...

【ArcGIS Pro二次开发】(74):Python、C#实现Excel截图导出图片

以村庄规划制图为例,通过对现状和规划用地的统计,生成Excel格式的【空间功能结构调整表】后,需要进一步将表格导出成图片,并嵌入到图集中,这样可以实现全流程不用手动参与,让制图的流程完全自动化。 关于E…...

74HC138逻辑芯片

文章目录 74系列逻辑芯片——74HC138基础信息描述特征应用范围 功能信息封装引脚基本电路 扩展性能分析 74系列逻辑芯片——74HC138 基础信息 描述 74HC138器件设计用于需要极短传播延迟时间的高性能存储器解码或数据路由应用;在高性能存储系统中,可使用…...

【架构图解】API架构图解:如何以图表形式展现复杂系统

文章目录 前言序列图组件图数据流程图结论 前言 架构图是链接到 API 的不同组件/服务如何相互交互的直观表示。 当需要理解 API 的架构并将其传达给不同的利益相关者(包括其他开发人员、项目经理和客户)时,这些图表非常有用。 图表/视觉效…...

D-link未授权访问以及远程代码执行

随便输入一个错误密码,会跳转到页面: /page/login/login.html?errorfail继续访问有效页面漏洞url: /Admin.shtml然后访问管理页面去更改管理密码 直接构造payload访问漏洞url: /cgi-bin/execute_cmd.cgi?cmdid执行命令&#…...

flask踩坑集锦

很久之前用过flask,那时候是跟着教程,教程怎么做我就怎么做,没有仔细考虑过。 现在是全靠文档和搜索一步一步搭建,忘了很多东西,就碰了很多壁,浅浅记录一下子。 1.Jinja2的模板继承,是指抽出每…...

VulnHub jarbas

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏…...

基因预测软件prodigal的使用

Prodigal是一款常用的基因预测软件,可以用于预测原核生物基因组中的开放阅读框(ORF),并根据不同的编码调用方式(如起始密码子和终止密码子)对其进行注释。 以下是使用Prodigal进行基因预测的步骤&#xff…...

银行存取款系统

题目 ​ 一个简单的存取款系统,用户可以选择存钱、取钱、转账、修改密码和退出系统等业务。程序使用了菜单界面来展示业务选项,并根据用户的选择调用相应的函数进行处理。具体功能如下: 登录:实现登录功能,需要输入正确密码才能进入菜单系统。 菜单:显示菜单界面,列出其…...

ConnectionError: HTTPSConnectionPool

ConnectionError: HTTPSConnectionPool(host‘zbbfxstatic.figtingdream.com’, port443): Max retries exceeded with url: /api/cache (Caused by NewConnectionError(‘<urllib3.connection.HTTPSConnection object at 0x00000249795AD9A0>: Failed to establish a ne…...