本以为学会了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 强化练习 (六)的更多相关文章

  1. SQL总结(六)触发器

    SQL总结(六)触发器 概念 触发器是一种特殊类型的存储过程,不由用户直接调用.创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行. 触发器可以查询其他表,而且可以包含复杂的 S ...

  2. 漏洞重温之sql注入(六)

    漏洞重温之sql注入(六) sqli-labs通关之旅 Less-26 进入第26关,首先我们可以从网页的提示看出本关是get型注入. 我们给页面添加上id参数后直接去查看源码. 需要关注的东西我已经 ...

  3. SQL学习笔记六之MySQL数据备份和pymysql模块

    mysql六:数据备份.pymysql模块   阅读目录 一 IDE工具介绍 二 MySQL数据备份 三 pymysql模块 一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测 ...

  4. SQL入门经典(六) 之视图

    视图实际上就是一个存储查询,重点是可以混合和匹配来自基本表(或其他视图)的数据,从而创建在很多方面象另一个普通表那样的起的作用.可以创建一个简单的查询,仅仅从一个表(另一个视图)选择几列或几行,而忽略 ...

  5. JavaScript强化教程 - 六步实现贪食蛇

    1.首先创建div 并且给div加样式 <div id="pannel" style="width: 500px;height: 500px;z-index: 1; ...

  6. SQL Server(六)——索引、视图和SQL编程

    1.索引 添加索引,设计界面,在任何一列前右键--索引/键--点击进入添加某一列为索引 2.视图 视图就是我们查询出来的虚拟表 创建视图:create view 视图名 as SQL查询语句,分组,排 ...

  7. PL/SQL学习(六)触发器

    原文参考:http://plsql-tutorial.com/ 创建语法: CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE | AFTER | IN ...

  8. 抓取锁的sql语句-第六次修改

    增加异常处理 CREATE OR REPLACE PROCEDURE SOLVE_LOCK AS V_SQL VARCHAR2(3000); --定义 v_sql 接受抓取锁的sql语句V_SQL02 ...

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

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

  10. SQL随记(六)

    1.关于dbms_sql包的一些执行语句 cursor_name := DBMS_SQL.OPEN_CURSOR; --打开游标: DBMS_SQL.PARSE(cursor_name, var_dd ...

随机推荐

  1. Flume - [05] Hbase sink

    一.概述   此接收器将数据写入Hbase.Hbase配置是从类路径中遇到的第一个Hbase-site.xml获取的.由配置指定的实现 HbaseEventSerializer 的类用于将事件转换为 ...

  2. Scala高阶函数 1

    package com.wyh.day01 /** * * 高阶函数 */ object ScalaFun3 { def main(args: Array[String]): Unit = { //定 ...

  3. MySql 主从(备)部署 | 冷备份

    前言 MySQL 主从复制(Master-Slave Replication)是一种常见的数据库架构设计,用于提高数据可用性.实现读写分离以及支持备份策略.冷备份是指在数据库关闭状态下进行的数据备份方 ...

  4. golang倒腾一款简配的具有请求排队功能的并发受限服务器

    golang官方指南给了一些代码片段来,层层递进演示了信道的能力: 1>. 信号量 2>. 限流能力 var sem = make(chan int, MaxOutstanding) fu ...

  5. c++中的类成员函数指针

    c++中的类成员函数指针 文章目录 c++中的类成员函数指针 发生的事情 正常的函数指针定义 定义类的成员函数指针 std::function 发生的事情 最近,想用一个QMap来创建字符串和一个函数 ...

  6. Linux 安装 MySQL 8.0

    目录 下载 安装数据库 修改mysql配置文件(若没有则新建) 安装并初始化mysql 查看mysql密码 配置启动 登录MySQL 修改密码 配置远程连接 配置防火墙 常见错误 Windows 安装 ...

  7. .NET8中gRPC的使用

    在现代分布式系统中,服务之间的通信是一个非常重要的环节.随着微服务架构的流行,服务之间的通信方式也在不断演进.gRPC作为一种高性能.跨语言的RPC框架,逐渐成为了我们的首选. 一.简介 gRPC 是 ...

  8. Shell脚本实现服务器多台免密

    简介 本脚本(auto_ssh_batch.sh)用于在多台主机之间快速配置SSH免密登录,并支持远程传输脚本/文件及执行命令.通过 pass 文件提供统一认证凭据,通过 nodes 文件定义目标主机 ...

  9. C# 从零开始使用Layui.Wpf库开发WPF客户端

    一.简介 最近需要开发一个桌面版的工具软件,之前用得更多的是Winform,作为一个全干工程师,我们也要兼顾下WPF,趁此机会再研究下开源控件库. MaQaQ:Winform真好用(有个HZHCont ...

  10. FastAPI依赖注入:从基础概念到应用

    title: FastAPI依赖注入:从基础概念到应用 date: 2025/04/04 16:28:51 updated: 2025/04/04 16:28:51 author: cmdragon ...