SQL连接与筛选:解析left join on和where的区别及典型案例分析

文章目录

  • 前言
  • 数据库在运行时的执行顺序
  • 一、left join on和where条件的定义和作用
    • left join on条件
    • where条件
  • 二、left join on和where条件的区别
    • 原理不同
      • left join原理:
      • where原理:
    • 应用场景不同
    • 执行顺序不同(作用阶段不同)
    • 结果集不同
  • 三、实际案例理解left join on和where条件
    • 建表
    • 案例实操
      • 使用left join on的查询语句:
        • 常规案例-on主外键
        • 变形1-on其他列
        • 变形2-on多个条件
        • ~变态变形3-on无关联字段
      • 使用where条件的查询语句:
    • 总结:
  • TODO后续

在这里插入图片描述

前言

作为一名Java(CRUD)开发工程师,与数据库打交道的时间可不少,我们在编写SQL语句时,经常会用到left join on和where条件来过滤数据,对于初学者来说,都会遇到一个经典问题:left join on后面的条件和where条件的区别到底是什么?

还记得在刚工作那会,我就写过2篇针对left join on相关的文章,最近又看了下之前的文章,发现又有了新的体会,

注意区分left join on 后面的条件 和where 后面的条件------这篇有点low了
测试一下你真的理解数据库左连接了吗?--------这篇说实话可以结合我写的例子看看你自己是否掌握了数据库的left join on左连接

本篇文章我将深入探讨left join on后面条件和where条件的异同,并通过实际SQL案例进行详细解析,帮助大家理解和应用这两个关键的查询语句。

数据库在运行时的执行顺序

这是数据库真正在运行时的底层执行顺序,必须要记住,这有利于我们写出更好的SQL,同时也可以发现on和where作用的时机也不一样!!!

(8)SELECT (9) DISTINCT (11)< Top Num> < select list>
(1) FROM [left_table]
(3)<join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH <CUBE | RollUP>
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>

img

一、left join on和where条件的定义和作用

left join on条件

在SQL语句中,left join on条件是用来指定两个表之间相关字段的连接方式。它用于联结两个表,返回左表中所有的记录以及符合连接条件的右表记录。 left join on条件通常结合on子句使用,格式如下:

SELECT 列名
FROM 表名1
LEFT JOIN 表名2
ON 表名1.列名 = 表名2.列名

where条件

where条件则是用于过滤记录的条件语句。它用于对查询结果进行进一步筛选,只选择满足条件的记录。where条件可以组合多个条件,使用逻辑运算符(如AND、OR)来连接。格式如下:

SELECT 列名
FROM 表名
WHERE 条件1 AND 条件2 ...

二、left join on和where条件的区别

原理不同

  • on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。

  • where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

具体一步步分析一下:

left join原理:

  1. 遍历左表中的每一条记录。
  2. 对于左表中的每一条记录,尝试在右表中找到匹配的记录(注意如果右边找到多条,左表重复展示,右边分别展示对应的数据),匹配条件由ON子句指定。
  3. 如果找到匹配的记录,则将这两条记录合并成一条新记录,并添加到结果集中。
  4. 如果未找到匹配的记录,则将左表的记录与NULL值合并成一条新记录,并添加到结果集中。

特别需要注意上面第2点,遍历过程中如果右边找到多条,左表重复展示,右边分别展示对应的数据,下面会有例子帮助理解

where原理:

  1. 从表中检索出所有记录。
  2. 对每一条记录应用WHERE子句中的条件表达式。
  3. 如果记录满足条件表达式,则将其包含在结果集中。
  4. 如果记录不满足条件表达式,则将其排除在结果集之外。
  • 这里也可以注意第2点,对于每一条记录都应用WHERE子句中的条件进行过滤,也就是如果不符合就是左边和右边都不会显示,
  • 而上面left join on是对于不符合的会将左表记录与NULL值合并成一条记录添加到结果集,也就是左表记录数据一定会展示出来!

应用场景不同

  • left join on常用于连接两个或多个表,并显示左表中所有记录以及匹配的右表记录。它适用于需要获取连接表间所有数据的场景。

  • 而where条件则是用于在查询结果上进行进一步的筛选和限定,通常是基于某些列的具体值或范围进行选择。

执行顺序不同(作用阶段不同)

  • left join on是在连接过程中确定两个表之间的连接条件,并将满足条件的记录组合在一起。也就是LEFT JOIN 发生在数据连接阶段!

  • 而where条件是在连接完成后对结果集进行筛选和过滤。也就是WHERE 条件发生在数据筛选阶段!

结果集不同

  • left join on会返回左表的所有记录以及符合连接条件的右表记录,即使条件不满足也会返回左表的数据。

  • 而where条件只会返回满足条件的记录。

三、实际案例理解left join on和where条件

为了更深入地理解left join on和where条件的区别,让我们来看一个实际案例。

建表

注意这里的建表语句跟我之前文章的测试一下你真的理解数据库左连接了吗?一模一样,可以两篇一起理解看看!

假设我们有两张表:大学学生大学选修班级来模拟大学生选修课程,。其中选修班级包括选修班级名称cname ,是否删除is_delete学生表包括学生的姓名name、班级class_id、以及选修班级的课程(这里采用hobby字段标识),

选修班级表t_class如下:

  • 注意这里Java课程有2条记录,其中一条是is_delete=1已经逻辑删除了,其中一条是正常启用的
DROP TABLE IF EXISTS `t_class`;
CREATE TABLE `t_class`
(
    `cid`       int(11)       NOT NULL AUTO_INCREMENT,
    `cname`     varchar(255)           DEFAULT NULL comment '选修班级名称',
    `is_delete` smallint(255) NOT NULL DEFAULT 0 comment '是否逻辑删除',
    PRIMARY KEY (`cid`) USING BTREE
);

-- ----------------------------
-- Records of t_class
-- ----------------------------
INSERT INTO `t_class` VALUES (1, 'Java', 0);
INSERT INTO `t_class` VALUES (2, 'Python', 0);
INSERT INTO `t_class` VALUES (3, 'C语言', 0);
INSERT INTO `t_class` VALUES (4, 'Java', 1);
cidcnameis_delete
1Java0
2Python0
3C语言0
4Java1

学生信息t_student如下:

  • 注意这里采用hobby字段代表学生选修班级的名称,正常这里用选修班级id关联就可以了,有时候我们为了查询方便会多冗余一下别的字段
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student`
(
    `id`       int(11) NOT NULL AUTO_INCREMENT,
    `name`     varchar(255) DEFAULT NULL comment '学生姓名',
    `class_id` int(11) NULL DEFAULT NULL comment '选修班级id',
    `hobby`    varchar(255) DEFAULT NULL comment '选修班级名称',
    PRIMARY KEY (`id`) USING BTREE
);
-- ----------------------------
-- Records of t_student
-- ----------------------------
INSERT INTO `t_student` VALUES (1, '小王', 1, 'Python');
INSERT INTO `t_student` VALUES (2, '小红', 2, 'Java');
INSERT INTO `t_student` VALUES (3, '小明', 3, 'C语言');
INSERT INTO `t_student` VALUES (4, '小李', 4, 'Java');
idnameclass_idhobby
1小王1Python
2小红2Java
3小明3C语言
4小李4Java

案例实操

现在我们想查询每个学生以及他们的选修课程,即使没有选修课程记录,也要显示学生信息。

使用left join on的查询语句:

常规案例-on主外键

正常的我们用学生表的class_id关联课程表的cid即可

select * from t_student s left join t_class c on  s.class_id=c.cid
idnameclass_idhobbycidcnameis_delete
1小王1Python1Java0
2小红2Java2Python0
3小明3C语言3C语言0
4小李4Java4Java1

这种是我们最常见的例子,接下来我们看看另外一种变形

变形1-on其他列

如果我们想用想学生表的选修班级名字去关联班级名称呢?SQL也很简单,但是对应的结果大家可以好好也猜一下

select * from t_student s left join t_class c on  s.hobby=c.cname
idnameclass_idhobbycidcnameis_delete
1小王1Python2Python0
2小红2Java1Java0
2小红2Java4Java1
3小明3C语言3C语言0
4小李4Java1Java0
4小李4Java4Java1

我们可以发现关联出来的小红和小李他们的记录会有2行,这是为什么?有注意到我们刚刚上面提到的left join on的原理执行步骤吗:

  1. 遍历左表中的每一条记录。
  2. 对于左表中的每一条记录,尝试在右表中找到匹配的记录(注意如果右边找到多条,左表重复展示,右边分别展示对应的数据),匹配条件由ON子句指定。
  3. 如果找到匹配的记录,则将这两条记录合并成一条新记录,并添加到结果集中。
  4. 如果未找到匹配的记录,则将左表的记录与NULL值合并成一条新记录,并添加到结果集中。

注意到上面第2点,遍历过程中如果右边找到多条,左表重复展示,右边分别展示对应的数据,对应这个例子就是小红选修的课程有2条记录,其中一条是正常启用的,一条是废弃删除的

变形2-on多个条件

假如现在我们想查询每个学生以及他们选修了Java课程的,即使没有选修Java课程记录,也要显示学生信息。

select * from t_student s left join t_class c on  s.hobby=c.cname and s.hobby='Python'
idnameclass_idhobbycidcnameis_delete
1小王1Python2Python0
2小红2Java
3小明3C语言
4小李4Java

我们先把条件拆解,然后按着上面这个步骤一步步来
第1步执行完select * from t_student s left join t_class c on s.hobby=c.cname 就是上面的结果

idnameclass_idhobbycidcnameis_delete
1小王1Python2Python0
2小红2Java1Java0
2小红2Java4Java1
3小明3C语言3C语言0
4小李4Java1Java0
4小李4Java4Java1

接着我们再看on的另外一条件 s.hobby='Python',同时结合这两个步骤

  • 如果找到匹配的记录,则将这两条记录合并成一条新记录,并添加到结果集中。
  • 如果未找到匹配的记录,则将左表的记录与NULL值合并成一条新记录,并添加到结果集中。

所以我们就是在上面的表格上进行过滤,只保留cname='Python’的班级,对于找不到的班级,就用NULL与左表合并显示,所以我们的左边的记录一定是完整的!

最终得到的结果就应该班级表只有Python信息,但是左表学生全部都会查询展示信息

idnameclass_idhobbycidcnameis_delete
1小王1Python2Python0
2小红2Java
3小明3C语言
4小李4Java

同理,如果改成select * from t_student s left join t_class c on s.hobby=c.cname and s.hobby='Python'呢?如果真的理解了应该很容易想出答案!

idnameclass_idhobbycidcnameis_delete
1小王1Python
2小红2Java1Java0
2小红2Java4Java1
3小明3C语言
4小李4Java1Java0
4小李4Java4Java1
~变态变形3-on无关联字段

前面的3个案例都是t_class和t_student有关联字段将两者关联在一起了,那么如果我没关联字段,阁下又当如何应对?

这个案例是我在文章测试一下你真的理解数据库左连接了吗?的最后一个例子,结果比较奇葩,正常也不会有这样关联的,大家可以蛮看理解一下!

select * from t_student s left join t_class c on s.hobby='Python'

结果如下:

idnameclass_idhobbycidcnameis_delete
1小王1Python1Java0
1小王1Python2Python0
1小王1Python3C语言0
1小王1Python4Java1
2小红2Java
3小明3C语言
4小李4Java

关键在于 left join 的条件 s.hobby = 'Python'。由于这个条件与 t_class 表无关,它实际上会导致一个笛卡尔积,然后根据这个条件来进行筛选

这个查询实际上会对 t_student 表中的每一行进行左连接,但 left join 的条件是 s.hobby = 'Python'。因为这个条件与 t_class 表无关,所有的行都会被保留,t_class 表的列会根据条件 s.hobby = 'Python' 来填充。

  • 对于 id=1 这一行,hobby'Python',所以会与 t_class 表的所有行进行左连接,因为 hobby = 'Python' 的条件总是成立。
  • 对于 id=2, id=3, 和 id=4 的行,hobby 分别是 'Java''C语言',所以 t_class 表的所有列都是 NULL

总结一下就是:查询的结果是对于每一个 t_student 表的行,如果 hobby == 'Python',则会与 t_class 表的所有行进行连接,否则 t_class 表的所有列都是 NULL。结果中包含了所有 t_student 表的行,并且根据 hobby 是否为 'Python' 来决定 t_class 表的列是否填充。

使用where条件的查询语句:

我们看看将上面变形2的on的另外一个条件放在where是怎样的?

select * from t_student s left join t_class c on  s.hobby=c.cname where s.hobby='Python'

先再看下上面的where原理执行步骤:

  1. 从表中检索出所有记录。
  2. 对每一条记录应用WHERE子句中的条件表达式。
  3. 如果记录满足条件表达式,则将其包含在结果集中。
  4. 如果记录不满足条件表达式,则将其排除在结果集之外。
  • 这里特别注意第2点,对于每一条记录都应用WHERE子句中的条件进行过滤,也就是如果不符合就是左边和右边都不会显示,
  • 而上面LEFT JOIN ON是对于不符合的会将左表记录与NULL值合并成一条记录添加到结果集,也就是左表记录数据一定会展示出来!

执行结果如下:也很好理解对于where里面符合的条件s.hobby='Python'会正常展示一行,而不符合的就直接整行不展示,而不是保留左边值,右边显示NULL

idnameclass_idhobbycidcnameis_delete
1小王1Python2Python0

而对于把条件过滤改成Java,执行结果应该也能很好理解了

select * from t_student s left join t_class c on  s.hobby=c.cname where s.hobby='Java'
idnameclass_idhobbycidcnameis_delete
2小红2Java1Java0
4小李4Java1Java0
2小红2Java4Java1
4小李4Java4Java1

总结:

  • 通过对比上述left join on 和where两个查询语句,我们可以发现在使用left join on时,即使没有选修课程记录,学生的信息也会显示出来,而在使用where条件时,要是选修课程的条件不满足,就直接整行不显示了,区别还是很大的!
  • left join on主要用于连接表和显示所有记录,而where条件则用于对结果进行进一步筛选。平常工作中我们一定要理解这两者的区别和原理,才能正确地用好这两个关键的查询语句!

TODO后续

日常工作中写SQL,我们会经常left join一堆表,我最多见过的有20多张的。。。(在一家外企,然后还用了一堆存储过程有几千行的,吐了。。。)那么对于left join on和前面表关联条件的时候,有的时候是紧挨着的表,有的是隔开的,有啥区别呢?具体看看这个

a 表主键是aid,b表是bid,c表是cid,以下两个语句有什么区别?如何理解?
篇幅有限。详见下文~

select * from  a left join b on a.aid=b.aid  left join c on b.bid=c.bid

select * from  a left join b on a.aid=b.aid  left join c on a.aid=c.aid

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/744288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文入门Makefile

今天我们来玩玩Makefile。 这边是借鉴的陈皓老师的《跟我一起写 Makefile》 pdf下载链接如下。 链接&#xff1a;https://pan.baidu.com/s/1woRq2nEkgzLv1o5uE0FZHg?pwdmhrh 提取码&#xff1a;mhrh 我们之前已经算是入门了gcc&#xff0c;那我们的下一站就是Makefile&…

每日一题——Python实现PAT甲级1144 The Missing Number(举一反三+思想解读+逐步优化)四千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 时间复杂度分析 空间复杂度分析 总体空间复杂度&#xff1a;O(N) 总结 我…

洗地机什么牌子耐用?四款高品质洗地机型号强烈安利

在快节奏的现代生活中&#xff0c;保持家庭清洁成为了许多人的挑战。传统的清洁方式不仅耗时费力&#xff0c;还难以彻底清洁地板上的污渍和毛发。特别是对于有宠物的家庭&#xff0c;毛发的清理更是让人头疼。如果有一款洗地机&#xff0c;既能高效清洁又能省时省力&#xff0…

Matlab|风光及负荷多场景随机生成与缩减

目录 1 主要内容 计算模型 场景生成与聚类方法应用 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序方法复现了《融合多场景分析的交直流混合微电网多时间尺度随机优化调度策略》3.1节基于多场景技术的随机性建模部分&#xff0c;该部分是随机优化调度的重要组成部分…

从0到1构建自己的短链接系统

1. 短链系统简介 1.1 短链系统的定义与用途 短链系统是指将一个较长的URL地址&#xff0c;通过特定的算法生成一个较短的、具备唯一性的URL地址。这种系统广泛应用于社交网络、短信、邮件营销等场景&#xff0c;它能帮助用户在字数受限的情况下分享链接&#xff0c;并且还具有…

6-47选择整数计算

整数计算&#xff1a; 用swing组件来实现整数计算&#xff0c;需要对整数计算的值进行校验。 import javax.swing.*; import java.awt.*; import java.awt.event.*;public class IntegerCalculator extends JFrame implements ActionListener {private JCheckBox[] checkBoxe…

老杨说运维 | 基于业务全链路的端到端排障分析(文末附现场视频)

前言 青城山脚下的滔滔江水奔涌而过&#xff0c;承载着擎创一往无前的势头&#xff0c;共同去向未来。2024年6月&#xff0c;双态IT成都用户大会擎创科技“数智化可观测赋能双态运维”专场迎来了完满的收尾。 本期回顾来自擎创科技产品总监殷传旺的现场演讲&#xff1a;云原生…

封装了一个iOS联动滚动效果

效果图 实现逻辑和原理 就是在 didEndDisplayingCell 方法中通过indexPathsForVisibleItems 接口获取当前可见的cell对应的indexPath&#xff0c; 然后获取到item最小的那一个&#xff0c;即可&#xff0c;同时&#xff0c;还要在 willDisplayCell 方法中直接设置标题的选中属…

代码随想录算法训练营第三十四天|56. 合并区间、738.单调递增的数字、968.监控二叉树

56. 合并区间 题目链接&#xff1a;56. 合并区间 文档讲解&#xff1a;代码随想录 状态&#xff1a;无语&#xff0c;这题从右边界排序做不了&#xff01; 思路&#xff1a; 排序&#xff1a;按照区间的起始位置进行排序&#xff0c;这样后面处理时可以顺序合并重叠区间。合并…

Cortex-M Fault

Cortex-M CPU 会在系统发生故障时引发异常。非法内存写入和读取、访问未通电的外设、执行无效指令、除以零以及其他问题都可能导致此类异常。通常在所有情况下都会引发 HardFault 异常。对于某些故障&#xff0c;可以启用不同的异常来专门处理这些情况。 Cortex-M 故障异常 …

剪画小程序:视频文案提取神器:制作爆款视频的第一步!

在这个信息爆炸的时代&#xff0c;视频成为了我们获取知识和娱乐的重要途径。 但有时候&#xff0c;我们想要的不仅仅是观看视频&#xff0c;而是能够将其中精彩的文案提取出来&#xff0c;为自己的创作添砖加瓦。 现在&#xff0c;有一款神奇的工具应运而生&#xff0c;为您…

Linux-笔记 全志T113移植正点4.3寸RGB屏幕笔记

目录 前言 线序整理 软件 显示调试 触摸调试 背光调试 前言 由于手头有一块4.3寸的RGB屏幕(触摸IC为GT1151)&#xff0c;正好开发板上也有40Pin的RGB接口&#xff0c;就想着给移植一下&#xff0c;前期准备工作主要是整理好线序&#xff0c;然后用转接板与杜邦线连接验证好…

Vitis Accelerated Libraries 学习笔记--Vision 库的组织结构

1. 简介 Vision 库的组织结构如下&#xff1a; ├── L1/ │ ├── README.md │ ├── examples/ │ ├── include/ │ ├── lib/ │ └── tests/ ├── L2/ │ ├── README.md │ ├── examples/ │ └── tests/ ├── L3/ │ ├── R…

突破架构瓶颈:克服软件系统中的漂移和侵蚀

一种常见但不完美的比喻是将软件系统中的架构漂移和侵蚀与物理建筑的架构相比。虽然这个比喻很直观&#xff0c;但它存在一个根本性的误解&#xff0c;这也常常引发软件开发中的架构问题。 试想一下&#xff0c;一个设计良好的摩天大楼或房屋建成后&#xff0c;我们期望它基本保…

本地电脑配置不足,对工业仿真计算有哪些影响?

工业仿真计算对电脑的要求相对较高&#xff0c;这主要是因为仿真过程涉及到大量的数据处理和复杂的计算任务。一个高效的工业仿真系统需要强大的计算能力和稳定的运行环境&#xff0c;以确保仿真的准确性和实时性。 工业仿真对电脑配置有哪些要求 首先&#xff0c;工业仿真计算…

Prompt 提示词工程:翻译提示

近期在对计算机学习时&#xff0c;许多内容需要看原始的英文论文&#xff0c;对于我这种学渣来说特别不友好&#xff0c;&#x1f937;&#x1f3fb;‍♀️无奈只能一边看翻译&#xff0c;一边学习。 之前有搜到过专门的翻译工具&#xff0c;无奈都是按照字数算费用的&#xf…

都2024年了,现在互联网行情怎样?

都2024年了&#xff0c;互联网行情是怎样的&#xff1f; 很直白的说&#xff0c;依旧是差得很&#xff0c;怎么说&#xff1f; 我刚在掘金上看到一个掘友写的文章&#xff0c;他是四月领了大礼包&#xff0c;据他的描述如下&#xff1a; 互联网行情依旧是差得很&#xff0c;很…

自编码器笔记

编码器解码器自编码器 先压缩特征&#xff0c;再通过特征还原。 判断还原的和原来的是否相等 encode data 在一个“潜在空间”里。它的用途是“深度学习”的核心-学习数据的特征并简化数据表示形式以寻找模式。 变分自编码器&#xff1a; 1. 首先、假设输入数据是符合正态分布…

DDL-表操作-数据类型

一.DDL-表操作-数据类型 MySQL中的数据类型有很多,主要分为三类:数值类型,字符串类型,日期类型。 二.关系表 注意: 无符号和有符号的取值范围不是一样的,无符号需要加上UNSIGNED范围。 BLOB&#xff1a;用来描述二进制数据 TEXT:用来描述字符串 三.定长字符串和变长字符串 c…

【UE5.3】笔记1

内容浏览器&#xff1a;存放项目中所有的资源&#xff1a;关卡、蓝图类...... 关卡--Map 至少有一个关卡&#xff0c;可以有多个关卡 -漫游 视野漫游&#xff1a;鼠标右键WASD QE 鼠标滑轮控制摄像机速度 运行&#xff0c;ESC退出运行,快捷键F8不停止运行单独弹出功能 -创…