「MySQL」查询方式(5k字长文!超详细!)
作者:mmseoamin日期:2024-04-01

🎇个人主页:Ice_Sugar_7

🎇所属专栏:数据库

🎇欢迎点赞收藏加关注哦!

查询方式

  • 🍉聚合查询
    • 🍌count
    • 🍌sum
    • 🍌group by
    • 🍉联合/多表查询(面试常考)
      • 🍌两个表的联合查询
      • 🍌多个表的联合查询
      • 🍌外连接
      • 🍉子查询
      • 🍉合并查询

        🍉聚合查询

        前面我们讲查询时带表达式,比如成绩表中有语文、数学、英语三个科目,我们要查询总分,就要用到:

        select chinese + math + english from...
        

        这种查询方式实际上是在进行列和列之间的运算

        而聚合查询,则是进行“行与行”之间的运算,不过这里行之间的运算有一定的限制——只能通过聚合函数来进行操作,这就需要用到SQL提供的一些库函数了。聚合查询不像表达式查询那样随便写表达式就可以了

        下面我们来看一下常用的聚合函数:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第1张

        🍌count

        现在有一个学生表:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第2张

        select count(*) from students;
        

        这行代码得到结果为4,它就相当于先执行:

        select * from students;
        

        然后再使用 count 来计算结果的行数

        大多数情况下,count(*)和count(列名)没什么区别,在特定情况下才会有差异

        比如,往上面的学生表中插入一个姓名为NULL的记录:「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第3张

        我们用 select count(*) 和 select count(name) 分别查询,得到的结果不一样

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第4张

        由此我们可以得出一个结论:查询指定列时,如果查询结果带有 null值,那么此时 null值的记录不会计入计数;而如果使用 count(*),则会计入计数

        🍌sum

        现在有如下的成绩表:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第5张

        通过sum可以得到总的语文成绩

        select sum(chinese) from grade;
        

        sum 可以把某一列的值全部放在一起相加,在这个过程中,会把 null 给忽略掉,也就是说此时 null 相当于 0

        除了数字求和,如果将名字进行求和会得到什么?

        select sum(name) from grade;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第6张

        可以看到只报警告而没有报错

        在SQL中,如果把字符串当作数字来进行算术运算,就会尝试把字符串转成数字。但是上面这些名字是无法转成数字的,所以报警告

        而如果我们插入一个数字字符作为名字的记录,那就可以转成数字了(不过现实中肯定没人这么起名的hhh)

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第7张

        这次就可以得到结果了:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第8张

        至此,我们已经介绍了 sum 的用法,剩下的 avg、min、max 的用法和 sum 基本类似,所以也就不再赘述了,接下来就直接用了

        现在我们要查询成绩表中,数学分数最低的同学:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第9张

        但是我们查询出来的姓名和成绩对不上!

        正常来说,一行数据每个列都是对应的(比如张一学号为1,数学考了80),这些列共同构成了一条记录。但是,如果查询中包含聚合函数和非聚合的列,那么结果中的列就不是对应的(相当于各打各的)

        这是在因为使用聚合函数的时候,列和列之间的顺序已经被“打散”了。所以大部分情况下,聚合的列和非聚合的列不能一起使用。当然,有一种情况例外,那就是 group by

        在此之前,先回到上面的例子,要找出数学成绩最低的同学,我们可以将 order by 和 limit 配合使用:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第10张

        (顺便提一句,order by 默认是按升序排序的)

        🍌group by

        刚才的聚合是把整个表所有行都聚合在一起,不过也可以先把所有行分成若干组,然后分别对每个组进行聚合,需要用到 group by

        group by 列名
        

        它的效果就是把指定的列,其中值相同的记录划分到一组,针对这些组就可以分别进行聚合查询了

        举个例子,比如现在要按照岗位,对职工表中员工的工资进行查询以及统计,就可以使用group by 了

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第11张

        在 select 列名的时候,列名是可以写role的,因为我们是按 role 来分组的

        但是注意不能写 id 或者 name,因为这样写的话你会发现一个记录它的列是对不上的,如下图:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第12张

        这就类似刚才上面查询数学成绩的同学这个例子

        总结一下就是:非聚合的列不能和聚合的列或者 group by 的列一起使用

        对于分组查询,它也是可以对查询结果进行条件筛选的,分组后的条件,用 having 来表示,它的用法和where是一样的,只不过 where 是用于分组之前的条件

        下面应用一下 having

        例1:要统计平均薪资高于10000的岗位

        select role,avg(salary) from emp group by role having avg(salary) > 10000;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第13张

        例2:要统计每个岗位的平均薪资,不包括李四,同时除去平均薪资低于13000的情况

        统计平均薪资的时候不包括李四,这是在分组之前进行的,要用where;而筛选出平均薪资高于13000的情况,这是在分组后进行的,要用 having

        select role,avg(salary) from emp where name != '李四' group by role having avg(salary) > 13000;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第14张


        🍉联合/多表查询(面试常考)

        前面的查询都是针对一张表的,而多表查询自然是针对多张表的,它比单表查询要复杂一些

        在正式讲多表查询之前,需要先引入一个概念——笛卡尔

        所谓笛卡尔积,其实就是简单的排列组合

        笛卡尔积的列数就是之前两个表的列数之和;而行数则是之前两个表的行数之积

        如果表更多,比如有三张表A、B、C,那么就是先计算 A 和 B 的笛卡尔积,算出来的结果再和 C 计算笛卡尔积

        (注意:将两个很大的表进行笛卡尔积是一个危险操作,因为会产生大量的运算和 IO,可能把数据库搞挂了)

        🍌两个表的联合查询

        联合查询的核心操作就是进行笛卡尔积,比如使用两个表进行联合查询,就是先把这两个表计算笛卡尔积

        比如同时查询学生表和成绩表:

        select * from students,grade;
        

        得到下面的结果:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第15张

        细看一下我们会发现,有一些记录是无效的,就学生表中的 id 对不上 成绩表中的 id

        所以我们再指定一些条件,来得到预期的查询结果

        我们要让两个表中 id 一样的记录才能配对

        select * from students,grade where students.id = grade.id;
        

        students.id = grade.id 这个把两个表连接起来的条件,就叫作连接条件

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第16张

        不过也不是随便拿来两个表就能进行笛卡尔积,一定要确保这两个表有一定的关联关系,即至少有一个列是有关联的

        总结:多表查询的一般步骤

        ①笛卡尔积

        ②连接条件

        ③根据需求指定其他条件

        ④针对列进行精简 or 使用聚合函数

        除了上面的写法之外,联合查询还有一种写法,也能实现一样的效果:

        select * from 表1 join 表2 on 连接条件;
        

        所以上面的例子,我们也可以写为

        select * from students join grade on students.id = grade.id;
        

        可以得到一样的结果

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第17张

        再来看一个例子

        现有学生表和课程表这两个表

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第18张

        现在要求每位同学所有课程的总分

        思路:按照上面的步骤,先笛卡尔积,然后指定连接条件

        我们要查看的列就是姓名和总分这两列

        select students.name,sum(course.score) from students,course where students.id = course.student_id;
        

        然后根据需求指定其他条件:因为我们是要统计每一位学生的成绩,所以就要按学生名字进行分组,这就要用到 group by

        select students.name,sum(course.score) from students,course where students.id = course.student_id group by students.name;
        

        接下来就是对列进行精简或者使用聚合函数,因为我们的目的就是求和,所以一开始就已经使用聚合函数 sum 了,这一步就不用再考虑了

        🍌多个表的联合查询

        上面举的例子的中有学生表和课程表这两个表,现在要再加入另一个表——课程学分表,它包括课程名字和课程学分

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第19张

        那如何把它和前面两个表连接起来呢?

        我们可以发现,课程学分表和学生表之间其实没有联系,因为它们没有相关联的列;反之,它和课程表就很有联系——都有“课程名字”这一列

        所以先把它们俩连起来

        select * from course,credit where course.course_name = credit.course_name;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第20张

        接下来再把这个表和学生表连起来

        只需在原来的基础上,再查询一下学生表,并加上连接条件(即学生表的 id 和课程表的学生 id 相等),现在就有两个连接条件了,用 and 把两条件结合起来

        select * from students,course,credit where students.id = course.student_id and course.course_name = credit.course
        _name;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第21张

        不过查询结果的列数太多了,我们需要精简一下,三个表分别查询指定列就 ok 了

         select students.name,students.id,course.course_name,course.score,credit.credit from students,course,credit where
        students.id = course.student_id and course.course_name = credit.course_name;
        

        这条SQL语句看起来很长,但是我们拆分成一步步来写,其实也就没那么复杂了

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第22张

        上面的SQL语句也可以使用 join on 来改写:

        select students.name,students.id,course.course_name,course.score,credit.credit from students join course on stude
        nts.id = course.student_id join credit on course.course_name = credit.course_name;
        

        另外,在多表查询中,前面涉及到的去重、排序、limit 等操作也是同样适用的,具体就不演示了


        🍌外连接

        刚才上面那些写法,叫作内连接,而外连接也是多表查询的一种体现形式

        在大多数情况下,内连接和外连接的查询结果没什么区别,只有在一些特殊情况下,查询结果才会存在差异

        那么“大多数情况”是什么样的情况呢?举个例子:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第23张

        在上面的学生表和成绩表中,这两个表的数据是一一对应的,即学生表中的任何一个记录都能在分数表中体现出来;反过来,分数表中的每个记录,也能在学生表中体现出来,那此时外连接和内连接的结果就是一样的

        前面我们说可以使用 join on 进行联合查询,其实那里的 join 前面省略了 inner,它表示内连接,一般 inner 是不用写的

        而外连接分为左外连接和右外连接,需要在 join 前面分别加上 left 或 right

        举例,现有两张表

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第24张

        注意,课程表中没有赵六的信息

        分别对学生表和课程表进行左、右外连接,得到如下结果:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第25张

        可以发现左外连接的结果有赵六这条记录,右表中的列全为 NULL;而右外连接没有这条记录

        结论如下:

        ①左外连接就是以左表为主,保证左侧的表(join 左边的表)每个记录都体现在最终结果里,如果这个记录在右表中没有匹配,就把对应的列填成 NULL

        ②同理,右外连接就是以右表为主,保证右表中每个记录都存在,如果对应的数据在左表中没有,则会填成 NULL


        🍉子查询

        其实就是套娃,把多个简单 sql 合并为一个复杂的 sql

        注意:实际开发中不建议这样写,因为当有多个 sql 语句时,合并后就是一坨…

        我们不写 ≠ 别人不写,为了看懂别人写的子查询 sql,我们还是有必要学习一下

        举一个简单的例子,比如现在要从下面这个表中找出张一的同班同学的名字

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第26张

        照正常的思路,那就是先找出张一的班级:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第27张

        然后再找出1班中名字不是张一的同学:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第28张

        可以看到,在这个过程中,我们进行两次查询,先得到班级信息,然后由此进行第二次查询得到同学姓名

        使用子查询的话,那就是将上面这两步合并起来:

        select name from students where name != '张一' and classid = (select classid from students where name = '张一');
        

        🍉合并查询

        这个查询很好理解,就是把两个查询结果的结果集,合并成一个集合,这个过程我们使用 union 关键字来完成

        语法:

        select 1 union select 2
        

        注意:合并查询要求两个 select 查询的结果集的列数和类型要匹配,最终的列名就是第一个 select 的列名

        合并查询看起来和 or 差不多,但是 or 只能在一个表中进行查询,而 union 左右两侧的 sql 可以是查询两个不同的表,并且还会自动对查询结果进行去重(如果使用 union all 的话,则不会去重)

        下面还是举些例子运用 union:

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第29张

        select * from students where name = '张三' union select * from students where id = 1;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第30张

        select * from students where name = '张三' union select * from students where id = 2;
        

        「MySQL」查询方式(5k字长文!超详细!),在这里插入图片描述,第31张