当前位置: 首页 > 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 是…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

AspectJ 在 Android 中的完整使用指南

一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...