这两天在写一个权限的sql, 涉及 3 张表, 然后做了一个 union all 的操作, 感觉效率有点问题, 写套娃, 改来改去的做优化. 关键数据又不能贴, 嗯, 还是明天搞个假数据来说明这个关系. (PS. 多次测试出一个结论, 关于 mysql 的, select * 和 select 某字段, 二者性能无明显差异), 原因是, sql 执行的顺序是从 from ... where ... 这样开始的. select 的影响其实并不大.

SQL 顺序

写法: select > from > where > group by > having > order by > limit ...

执行: from > where > group by > having > select > order by > limit

还是先整理下, 有空再给贴一版假数据吧, 继续练习 sql 不能停.

表关系

需求 01

按平均成绩, 降序显示所有学生 的 所有课程的成绩, 以及平均成绩

分析

直接一步步来就行了,都分别给查询出来, 然后关联呀.

首先, 先查询一波 score 表的所有信息.

select * from score;
+------+------+-------+
| s_id | c_id | score |
+------+------+-------+
| 0001 | 0001 | 80 |
| 0001 | 0002 | 90 |
| 0001 | 0003 | 99 |
| 0002 | 0002 | 60 |
| 0002 | 0003 | 80 |
| 0003 | 0001 | 80 |
| 0003 | 0002 | 80 |
| 0003 | 0003 | 80 |
+------+------+-------+
8 rows in set (0.00 sec)

然后, 再根据 学号 做 group by 求出每个人的 平均成绩.

select
s_id,
avg(score)
from score
group by s_id

一定要注意, group by 后, 前面 select 的字段, 只能是 group by 中出现的, 或 聚合函数的字段, where 是在 group by 之前, 分组后的过滤是 having. 这些都是我这新手常写着写着就给弄错了.

+--------+--------------+
| 学号 | 平均成绩 |
+--------+--------------+
| 0001 | 89.6667 |
| 0002 | 70.0000 |
| 0003 | 80.0000 |
+--------+--------------+
3 rows in set (0.00 sec)

然后, 以第一张表为主表, 通过 学号, 将第二表给 "inner join " 拼接上.

select
a.*,
b.* from score as a
inner join (
-- 小表作为一个子查询
select
s_id,
avg(score) from score
group by s_id
) as b on a.s_id = b.s_id
+------+------+-------+------+------------+
| s_id | c_id | score | s_id | avg(score) |
+------+------+-------+------+------------+
| 0001 | 0001 | 80 | 0001 | 89.6667 |
| 0001 | 0002 | 90 | 0001 | 89.6667 |
| 0001 | 0003 | 99 | 0001 | 89.6667 |
| 0002 | 0002 | 60 | 0002 | 70.0000 |
| 0002 | 0003 | 80 | 0002 | 70.0000 |
| 0003 | 0001 | 80 | 0003 | 80.0000 |
| 0003 | 0002 | 80 | 0003 | 80.0000 |
| 0003 | 0003 | 80 | 0003 | 80.0000 |
+------+------+-------+------+------------+
8 rows in set (0.00 sec)

然后再 按 avg(score) 降序即可.

select
a.*,
b.* from score as a
inner join (
select
s_id,
avg(score) as avg_score from score
group by s_id
) as b on a.s_id = b.s_id order by b.avg_score desc;
+------+------+-------+------+-----------+
| s_id | c_id | score | s_id | avg_score |
+------+------+-------+------+-----------+
| 0001 | 0001 | 80 | 0001 | 89.6667 |
| 0001 | 0002 | 90 | 0001 | 89.6667 |
| 0001 | 0003 | 99 | 0001 | 89.6667 |
| 0003 | 0003 | 80 | 0003 | 80.0000 |
| 0003 | 0001 | 80 | 0003 | 80.0000 |
| 0003 | 0002 | 80 | 0003 | 80.0000 |
| 0002 | 0002 | 60 | 0002 | 70.0000 |
| 0002 | 0003 | 80 | 0002 | 70.0000 |
+------+------+-------+------+-----------+
8 rows in set (0.00 sec)

.... 似乎不是这样子的, 应该是要给平铺开来哦, 序号, 每门课, 成绩, 平均分嘛..

学号, 课程1, 课程2, 课程3, 平均分
0001, 90, 80, 80, 83.33333
select
s_id as "学号",
avg(score) as "平均成绩"
from score
group by s_id
order by avg(score) desc;
+--------+--------------+
| 学号 | 平均成绩 |
+--------+--------------+
| 0002 | 70.0000 |
| 0003 | 80.0000 |
| 0001 | 89.6667 |
+--------+--------------+
3 rows in set (0.00 sec)

要把 c_id 给加进来, 用过 group by 了嘛, 就不能直接加了哦, , 但可以用 聚合函数 + case when 的方式来弄呀.

select
s_id as "学号", -- max, min 都行的, group by s_id 了, 就一条记录
max(case when c_id="0001" then score else null end) as "语文",
min(case when c_id="0002" then score else null end) as "数学",
max(case when c_id="0003" then score else null end) as "英文", avg(score) as "平均成绩" from score
group by s_id
order by avg(score) desc;
+--------+--------+--------+--------+--------------+
| 学号 | 语文 | 数学 | 英文 | 平均成绩 |
+--------+--------+--------+--------+--------------+
| 0001 | 80 | 90 | 99 | 89.6667 |
| 0003 | 80 | 80 | 80 | 80.0000 |
| 0002 | NULL | 60 | 80 | 70.0000 |
+--------+--------+--------+--------+--------------+
3 rows in set (0.00 sec)

因此,这个练习的关键点在于 case when 条件为真 then xxx else yyy end 和 group by 的特点, 即用了 group by 后, select 只能放 group by 中出现的字段 或者聚合函数. 那这里就 这里用了小技巧, 取一条数据吗, 本来就一条,, 那就 直接 max() 或者 min() 都是一样的效果哦.

case when ..then..else ..end 跟 if ... else 的区别在于, case 用来查询字段, if ... else 用在存储过程, 自定义函数中等, 不能混用.

小结

  • 多对一 这种查询集关系, 相同 id 关联, 其实用 多的一方, 来 inner 或者 left join 就给 合并一起了.
  • 用了 group by 后, 前面的 select 中只能出现 group by 中的字段 或者 聚合函数,不然报错或没有意义,反误导
  • 多分类平铺开, 可用 case when 条件为真 then xxx else yyy end 结合聚合函数实现.

SQL 强化练习 (九)的更多相关文章

  1. SQL Server(九)——事务

    事务: 保障流程的完整执行,就像银行取钱,先在你账上扣钱,然后存入别人的账上:但是从你账上扣完钱了,突然网断了,对方没有收到钱,那么此时你的钱也没了,别人的钱也没加上,事务为了防止此类情况的出现. 事 ...

  2. SQL强化(一)保险业务

    保险业务 : 表结构 : sql语句 : /*1. 根据投保人电话查询出投保人 姓名 身份证号 所有保单 编号 险种 缴费类型*/SELECTt2.cust_name,t2.idcard,t4.pro ...

  3. SQL强化练习(面试与学习必备)

    一.经典选课题A 1.1.请同时使用GUI手动与SQL指令的形式创建数据库.表并添加数据. 题目:设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教 ...

  4. mybatis源码阅读-执行一个sql的流程(九)

    图解 图片来源:https://my.oschina.net/zudajun/blog/670373 Mapper接口调用原理 我们整合成Spring  直接使用Mapper就能执行对应的sql 表现 ...

  5. SQL系列(九)—— 子查询(subQuery)

    1.子查询 前面的系列介绍的都是简单的查询场景,其中都只涉及到单张表的数据检索.但是在日常是实际应用中,数据模型之间的关系都非常的复杂,数据的需求一般都是来源于多个数据模型之间的组合而成,即对应多张表 ...

  6. Influx Sql系列教程九:query数据查询基本篇二

    前面一篇介绍了influxdb中基本的查询操作,在结尾处提到了如果我们希望对查询的结果进行分组,排序,分页时,应该怎么操作,接下来我们看一下上面几个场景的支持 在开始本文之前,建议先阅读上篇博文: 1 ...

  7. Mysql常用sql语句(九)- like 模糊查询

    测试必备的Mysql常用sql语句,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1683347.html 前言 ...

  8. SQL入门经典(九) 之自定义函数

    UDF和存储过程很类似,用户自定义函数是一组有序的T-SQL语句,这些语句被预先优化和编译,并且可以作为一个单元来测试调用.UDF和存储过程的主要区别在于结果返回方式,为了能支持更多返回值,UDF比存 ...

  9. SQL强化(三) 自定义函数

    ---恢复内容开始--- Oracle中我们可以通过自定义函数去做一些逻辑判断,这样可以减少查询语句,提高开发效率 create  -- 创建自定义函数 or replace -- 有同名函数就替换, ...

  10. SQL强化(二) 在Oracle 中写代码

    一  : 关于查询中的转换 -- 字符串转换 一 : decode 函数 转换 SELECT DECODE ( PROTYPE.PRO_TYPE_DATE, 'L', '长', 'm', '短', ' ...

随机推荐

  1. C# 钩子函数使用

    1. 什么是钩子 hook(钩子)是windows提供的一种消息处理机制平台,是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通过 ...

  2. window本地部署deepseek

    window本地部署deepseek 学习自[[教程]DeepSeek本地免费部署教程,丝滑不卡顿!带你解锁隐藏功能!]https://www.bilibili.com/video/BV1viFaeB ...

  3. Normalizing flow 流模型 | CS236深度生成模型Lec8学习笔记

    主要参考资料:Stanford University CS236: Deep Generative Models Lec8. 这篇blog基本上是CS236 Lec8的刷课总结/刷课笔记. VAE 这 ...

  4. ServerMmon青蛇探针,一个超好用的服务器状态监控-搭建教程

    serverMmon(青蛇探针)是nodeJs开发的一个酷炫高逼格的云探针.云监控.服务器云监控.多服务器探针~. 在线演示:http://106.126.11.114:5880/ 主要功能: 全球服 ...

  5. Typecho美化之网页底部增加好久不见的底部样式

    好久不见之本站同款网站底部样式,效果见本站. 1.修改footer.php首先,在页脚文件footer.php文件的最下面放入以下代码: <!-- 好久不见 --> <div cla ...

  6. 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析

    从 Chrome 125 开始,支持了一个全新的 CSS 特性 - Anchor Positioning,翻译过来即是锚点定位. 在之前的文章中,我们较为系统的讲述了这个新特性的使用,感兴趣的可以翻开 ...

  7. linux服务器压力/性能测试命令

    linux命令下使用ab -c500 -n2000   http://www.test.cn  进行压力测试 在Linux命令行中,ab 是 Apache HTTP server benchmarki ...

  8. 【VMware by Broadcom】VMware 产品套件(2025)

    VMware 被 Broadcom 收购后(现为 VMware by Broadcom),重新调整了其产品部门并最终优化为了四个,分别是:VMware Cloud Foundation(VCF)部门. ...

  9. 什么是CPU?

    当你用手机刷短视频.用电脑玩游戏,或是使用智能手表查看健康数据时,这些设备的核心"大脑"--CPU(中央处理器)正在默默工作.它是现代计算设备的核心,但很多人对它一知半解.今天我们 ...

  10. pycharm clone GitHub 提示 OpenSSL SSL_read: Connection was reset, errno 10054

    配置界面 错误提示 原因分析 clone的时候需要安全认证,当你在配置页面勾选上ssh ,就会报错 解决方案 在cmd里输入命令,然后再clone git config --global http.s ...