SQL 强化练习 (六)
本以为学会了Python 就已经天下无敌, 果然, 我还是太傻太天真了. 业务中几乎就没有用 Python 来直接连接数据库进行操作, 当然我是说数据这块哈. 哎, 难受, 还是用的 sql 这种方式. 但有个问题在于, sql 没有类似于编程语言那样来用个数据结构存储存储中间过程, 于是呢, 在写 "套娃" 就是 sql 嵌套的时候, 可难受了, 一不小心就会写乱, 阅读体验也不好, 但, 又没有其他的办法, 只能去多加练习去适应哦.
表关系

反复练习, 只能这样去提高理解了, 果然是唯手熟尔, 对此我深信不疑.
需求 01
-- 查询 没有学全所有课程的学生学号, 姓名
分析
student 表 left join score 表, 然后在 group by s_id 再 having 选课数量 < 实际有多少门课
-- 先看看总体情况
select
st.*,
sc.*
from student as st
left join score as sc
on st.s_id = sc.s_id
tips: 一定要用 left join 这样才不会漏掉有学生压根就没有选过课的情况
+------+-----------+------------+--------+------+------+-------+
| s_id | s_name | birth_date | gender | s_id | c_id | score |
+------+-----------+------------+--------+------+------+-------+
| 0001 | 王二 | 1989-01-01 | 男 | 0001 | 0001 | 80 |
| 0001 | 王二 | 1989-01-01 | 男 | 0001 | 0002 | 90 |
| 0001 | 王二 | 1989-01-01 | 男 | 0001 | 0003 | 99 |
| 0002 | 星落 | 1990-12-21 | 女 | 0002 | 0002 | 60 |
| 0002 | 星落 | 1990-12-21 | 女 | 0002 | 0003 | 80 |
| 0003 | 胡小适 | 1991-12-21 | 男 | 0003 | 0001 | 80 |
| 0003 | 胡小适 | 1991-12-21 | 男 | 0003 | 0002 | 80 |
| 0003 | 胡小适 | 1991-12-21 | 男 | 0003 | 0003 | 80 |
| 0004 | 油哥 | 1996-10-01 | 男 | NULL | NULL | NULL |
+------+-----------+------------+--------+------+------+-------+
果然, left join 就能把 "油哥" 这个兄弟, 一门课都不选的特例, 也给筛选出来了哦.
然后, "没有选全" , 也就是 group by 学生id, count(课程号) < 总课程数 了呗. 组内筛选用 having.
select
st.*,
sc.*
from student as st
left join score as sc on st.s_id = sc.s_id
group by st.s_id having
count(distinct sc.c_id) < (select count(distinct c_id) from course);
+------+--------+------------+--------+------+------+-------+
| s_id | s_name | birth_date | gender | s_id | c_id | score |
+------+--------+------------+--------+------+------+-------+
| 0002 | 星落 | 1990-12-21 | 女 | 0002 | 0003 | 80 |
| 0004 | 油哥 | 1996-10-01 | 男 | NULL | NULL | NULL |
+------+--------+------------+--------+------+------+-------+
这样不就, 获取到了 s_id 了吗, 然后在外面给套上一层, 就搞定了哦.
select
s_id as "学号",
s_name as "姓名"
from student where s_id in (
select
st.s_id -- 只要学号即可
from student as st
left join score as sc on st.s_id = sc.s_id
group by st.s_id having
count(distinct sc.c_id) < (select count(distinct c_id) from course)
);
+--------+--------+
| 学号 | 姓名 |
+--------+--------+
| 0002 | 星落 |
| 0004 | 油哥 |
+--------+--------+
2 rows in set (0.00 sec)
需求 02
查询 至少有一门课, 与学号为 "0001" 的学生, 所学课程相同, 的学生学号和姓名.
分析
先看 0001 这个老铁选了哪些课, 然后从 score 中查出 选个这个课有哪些学生学号 不就行了嘛
select c_id from score where s_id = "0001";
+------+
| c_id |
+------+
| 0001 |
| 0002 |
| 0003 |
+------+
这个兄弟, 把 1,2,3 号课程都给选上了, 果然是学霸, 目测.
然后再看, score 中 也选择了这些课的学号有哪些.
select
s_id,
c_id
from score
where c_id in (
select c_id from score where s_id = "0001"
);
+------+------+
| s_id | c_id |
+------+------+
| 0001 | 0001 |
| 0003 | 0001 |
| 0001 | 0002 |
| 0002 | 0002 |
| 0003 | 0002 |
| 0001 | 0003 |
| 0002 | 0003 |
| 0003 | 0003 |
+------+------+
8 rows in set (0.00 sec)
这样就把跟 0001 同学有选相关的课程的所有兄弟的, 学号, 课号给 拉出来了. 然后, 需要再对学号进行去重, 同时呢, 还需要将 0001 自己给排除掉哦
select
s_id as "学号",
s_name as "姓名"
from student where s_id in (
select distinct s_id from score
where c_id in (
select c_id from score where s_id = "0001"
)
-- 排除自己
and s_id != "0001"
);
+--------+-----------+
| 学号 | 姓名 |
+--------+-----------+
| 0002 | 星落 |
| 0003 | 胡小适 |
+--------+-----------+
2 rows in set (0.00 sec)
当然, 也可以用 inner join 的方式, 当数据量比较大的时候, 感觉用 join 的方式会更加快一点哦
select
a.s_id as "学号",
a.s_name as "姓名"
from student as a
-- 内连接查出的学号
inner join (
select distinct s_id from score
where c_id in (
select c_id from score where s_id = "0001"
)
-- 排除自己
and s_id != "0001") as b
on a.s_id = b.s_id;
+--------+-----------+
| 学号 | 姓名 |
+--------+-----------+
| 0002 | 星落 |
| 0003 | 胡小适 |
+--------+-----------+
2 rows in set (0.00 sec)
小结
- 灵活应用 join, group by + having 这样的子查询的方式, "面向过程" 写sql, 就是一点点查出来.
- 当考虑数据量的时候, 如果先用的子查询, 在查询效率上, 可能也应多考虑 join 来进行配合使用
- 感觉sql 其实和面向过程的编程是一样的, 查一个表就取个别名, 然后继续查, 拼接, 或者套娃啥的, 感觉熟练了就会好还多的, 还是需要不断练习哦.
SQL 强化练习 (六)的更多相关文章
- SQL总结(六)触发器
SQL总结(六)触发器 概念 触发器是一种特殊类型的存储过程,不由用户直接调用.创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行. 触发器可以查询其他表,而且可以包含复杂的 S ...
- 漏洞重温之sql注入(六)
漏洞重温之sql注入(六) sqli-labs通关之旅 Less-26 进入第26关,首先我们可以从网页的提示看出本关是get型注入. 我们给页面添加上id参数后直接去查看源码. 需要关注的东西我已经 ...
- SQL学习笔记六之MySQL数据备份和pymysql模块
mysql六:数据备份.pymysql模块 阅读目录 一 IDE工具介绍 二 MySQL数据备份 三 pymysql模块 一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测 ...
- SQL入门经典(六) 之视图
视图实际上就是一个存储查询,重点是可以混合和匹配来自基本表(或其他视图)的数据,从而创建在很多方面象另一个普通表那样的起的作用.可以创建一个简单的查询,仅仅从一个表(另一个视图)选择几列或几行,而忽略 ...
- JavaScript强化教程 - 六步实现贪食蛇
1.首先创建div 并且给div加样式 <div id="pannel" style="width: 500px;height: 500px;z-index: 1; ...
- SQL Server(六)——索引、视图和SQL编程
1.索引 添加索引,设计界面,在任何一列前右键--索引/键--点击进入添加某一列为索引 2.视图 视图就是我们查询出来的虚拟表 创建视图:create view 视图名 as SQL查询语句,分组,排 ...
- PL/SQL学习(六)触发器
原文参考:http://plsql-tutorial.com/ 创建语法: CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE | AFTER | IN ...
- 抓取锁的sql语句-第六次修改
增加异常处理 CREATE OR REPLACE PROCEDURE SOLVE_LOCK AS V_SQL VARCHAR2(3000); --定义 v_sql 接受抓取锁的sql语句V_SQL02 ...
- SQL强化(一)保险业务
保险业务 : 表结构 : sql语句 : /*1. 根据投保人电话查询出投保人 姓名 身份证号 所有保单 编号 险种 缴费类型*/SELECTt2.cust_name,t2.idcard,t4.pro ...
- SQL随记(六)
1.关于dbms_sql包的一些执行语句 cursor_name := DBMS_SQL.OPEN_CURSOR; --打开游标: DBMS_SQL.PARSE(cursor_name, var_dd ...
随机推荐
- 解决Mac无法共享网络问题
前言 部分小伙伴在使用 Mac 共享网络会出现各种问题: 无法共享 共享后,手机无法连接网络 解决办法 重置网络即可. 三个步骤轻松解决 访达(Finder)前往文件夹:/Library/Prefer ...
- 微信小程序反编译~2022年
小程序反编译 前言 微信小程序反编译可以通过对小程序包进行反编来获取小程序源码,在一次信息收集的过程中对某公司的APP.微信公众号.小程序进行抓包数据分析寻找接口等有用的信息时,在抓包过程中由于微信的 ...
- k8s dashboard token 生成/获取
创建示例用户 在本指南中,我们将了解如何使用 Kubernetes 的服务帐户机制创建新用户.授予该用户管理员权限并使用与该用户绑定的承载令牌登录仪表板. 对于以下每个和的代码片段ServiceAcc ...
- containerd 配置使用私有镜像仓库 harbor
前言 当要从非安全的镜像仓库中进行 Pull.Push 时,会遇到 x509: certificate signed by unknown authority 错误提示: 这是由于镜像仓库是可能是 ...
- Go 1.20更新了那些内容
PGO的引入 Go 1.20 发布了配置文件引导优化(PGO)的预览版,使编译器能够根据运行时配置文件信息,执行应用程序和工作负载的特定性优化.提供要构建的配置文件,使编译器能够将应用程序的速度提高大 ...
- jquery submit 解决多次提交
jquery submit 解决多次提交 web应用中常见的问题就是多次提交,由于表单提交的延迟,有时几秒或者更长,让用户有机会多次点击提交按钮,从而导致服务器端代码的种种麻烦. 为了解决这个问题,我 ...
- 搭建自己的OCR服务,第一步:选择合适的开源OCR项目
一.OCR是什么? 光学字符识别(Optical Character Recognition, OCR)是指对文本资料的图像文件进行分析识别处理,获取文字及版面信息的过程. 亦即将图像中的文字进行识别 ...
- 如何在 Git 书写良好的 Commit Messages
如何在 Git 书写良好的 Commit Messages Why(为什么编写) | How(如何编写) Why A diff will tell you what changed, but only ...
- 【前端JSP思考】JSP中#{},${}和%{}的区别
JSP中#{},${}和%{}的区别: #{} #{}:对语句进行预编译,此语句解析的是占位符?,可以防止SQL注入, 比如打印出来的语句 select * from table where id=? ...
- Go 中 JSON 的序列化和反序列化
golang中对json的序列化/反序列化操作还是比较容易的, 序列化操作主要是通过encoding/json包的Marshal()方法来实现, 反序列化操作主要是通过encoding/json包的U ...