-- ########## 01、综合练习 ##########

-- 使用的表结构来自前面创建的"教师授课、学生选课并有课程成绩"这个数据库设计
-- studentinfo、teacherinfo、courseinfo、scoreinfo -- 1、查询姓张的老师的数量
SELECT COUNT(teacherid) AS 姓张的老师的数量
FROM teacherinfo
WHERE teachername LIKE '张%'; -- 2、查询每门功课选修的学生数量
-- 写法1、使用左连接
SELECT c.`coursename` AS 课程名称, temp.选修的学生数量
FROM courseinfo AS c
LEFT JOIN
(
SELECT courseid, COUNT(studentid) AS 选修的学生数量
FROM scoreinfo
GROUP BY courseid
) AS temp
ON c.courseid = temp.courseid;
-- 写法2、使用子查询
SELECT
c.`coursename` AS 课程名称,
(
SELECT COUNT(studentid)
FROM scoreinfo AS sc
WHERE sc.courseid = c.`courseid`
) AS 选修的学生数量
FROM courseinfo AS c; -- 3、查询个人平均成绩高于60分的学生编号、学生姓名 和 个人平均成绩(如果得到的人数超过2人,显示第二条记录和第三条记录)
SELECT temp.studentid AS 学生编号, s.studentname AS 学生姓名, temp.个人平均成绩
FROM
(
SELECT studentid, AVG(score) AS 个人平均成绩
FROM scoreinfo
GROUP BY studentid
HAVING AVG(score) > 60
) AS temp
LEFT JOIN studentinfo AS s
ON temp.studentid = s.studentid
LIMIT 1, 2; -- 4、查询男生的人数 和 女生的人数
SELECT studentgender AS 性别, COUNT(studentid) AS 人数
FROM studentinfo
GROUP BY studentgender; -- 5、查询同名同姓的学生人数
SELECT * FROM studentinfo;
INSERT INTO studentinfo VALUES(NULL, '甄姬', '女', 38); SELECT studentname AS 重名学生姓名, COUNT(studentid) AS 重名学生人数
FROM studentinfo
GROUP BY studentname
HAVING COUNT(studentid) > 1; -- 6、查询每门功课的平均成绩,结果按每门功课平均成绩升序排列,成绩相同时,按课程编号倒序排列
SELECT c.`coursename` AS 课程名称, temp.平均成绩
FROM courseinfo AS c
LEFT JOIN
(
SELECT courseid, AVG(score) AS 平均成绩
FROM scoreinfo
GROUP BY courseid
) AS temp
ON c.courseid = temp.courseid
ORDER BY temp.平均成绩 ASC, c.`courseid` DESC; -- 7、查询课程名称为数学,且数学成绩低于60分的学生姓名和分数
SELECT c.`coursename` AS 课程名称, s.`studentname` AS 学生姓名, sc.`score` AS 分数
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c ON sc.courseid = c.courseid AND c.coursename = '数学' AND sc.score < 60
INNER JOIN studentinfo AS s ON sc.studentid = s.studentid; -- 8、查询所有学生的选课信息(显示为:学生编号、学生姓名、课程名称,并单行显示)
SELECT temp.学生编号, temp.学生姓名, GROUP_CONCAT(temp.课程名称) AS 课程名称
FROM
(
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, c.`coursename` AS 课程名称
FROM studentinfo AS s
LEFT JOIN scoreinfo AS sc ON s.studentid = sc.studentid
LEFT JOIN courseinfo AS c ON sc.courseid = c.courseid
) AS temp
GROUP BY temp.学生编号; -- 9、查询任何一门课程成绩在60分以上的学生姓名、课程名称及成绩
SELECT s.`studentname` AS 学生姓名, c.`coursename` AS 课程名称, sc.`score` AS 分数
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c ON sc.courseid = c.courseid
INNER JOIN studentinfo AS s ON sc.studentid = s.studentid
WHERE sc.score > 60; -- 10、查询至少选修了两门课程的学生信息
-- 写法1、使用独立子查询
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid IN
(
SELECT studentid
FROM scoreinfo
GROUP BY studentid
HAVING COUNT(courseid) >= 2
);
-- 写法2、使用内连接
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
INNER JOIN
(
SELECT studentid
FROM scoreinfo
GROUP BY studentid
HAVING COUNT(courseid) >= 2
) AS temp
ON s.studentid = temp.studentid; -- 11、查询全部学生都选修了的课程编号以及课程名称(基于无脏数据)
SELECT courseid AS 课程编号, coursename AS 课程名称
FROM courseinfo
WHERE courseid IN
(
-- 在成绩信息表中,按课程编号分组,统计每组的学生编号数量,看看哪组的数量和学生信息表中学生数量一致,一致就说明是全部学生都选修的课程
SELECT courseid
FROM scoreinfo
GROUP BY courseid
HAVING COUNT(studentid) = (SELECT COUNT(studentid) FROM studentinfo)
); -- 12、查询个人的英语成绩比数学成绩高的学生信息
-- 思路:在成绩信息表中对行数据进行获取比较,操作起来比较麻烦
-- 考虑进行【行转列】的操作,这样就可以在一行中对不同的列的内容进行比较
-- 【行转列】技巧:从成绩信息表中通过课程名称对应的课程编号形成两个独立的集合,再把这两个集合根据学生编号进行内连接,
-- 这样就得到同一个学生的不同课程的新集合,即得到同一行中有不同课程成绩的新集合
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.`studentid` IN
(
SELECT temp1.studentid
FROM
(
-- 从成绩信息表中获取的个人英语成绩集合
SELECT studentid, score
FROM scoreinfo
WHERE courseid = (SELECT courseid FROM courseinfo WHERE coursename = '英语')
) AS temp1
INNER JOIN
(
-- 从成绩信息表中获取的个人数学成绩集合
SELECT studentid, score
FROM scoreinfo
WHERE courseid = (SELECT courseid FROM courseinfo WHERE coursename = '数学')
) AS temp2
ON temp1.studentid = temp2.studentid AND temp1.score > temp2.score
); -- 13、查询所有学生的编号、姓名、选课数量、总成绩
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, COUNT(sc.`courseid`) AS 选课数量, SUM(sc.`score`) AS 总成绩
FROM studentinfo AS s
LEFT JOIN scoreinfo AS sc ON s.studentid = sc.studentid
-- 按照学生编号进行分组,语法OK
GROUP BY s.studentid;
-- 按照学生编号 和 学生姓名进行分组,语法也OK,因为studentid是主键,久可以唯一标识记录了,加上studentname属于锦上添花
-- GROUP BY s.studentid, s.`studentname`;
-- 按照学生姓名进行分组,语法就不OK了,因为学生姓名有重名时,就会分到一组中了
-- group by s.studentname; -- 14、查询没有选修过张老师课程的学生信息
-- 思路:没有选修过张老师课程的学生有两种:选修了课程但是选的不是张老师的课程的学生 和 没有选修课程的学生
-- 这里正向思考比较麻烦,所以考虑逆向思考
-- 从学生集合中剔除那些选修了张老师课程的学生,剩下的就是没有选修张老师课程的学生
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid NOT IN
(
-- 选修了张老师课程的学生
SELECT sc.studentid
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c ON sc.courseid = c.courseid
INNER JOIN teacherinfo AS t ON c.teacherid = t.teacherid AND t.teachername = '张老师'
); -- 15、查询学过语文也学过数学的学生信息
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
INNER JOIN scoreinfo AS sc1
ON s.studentid = sc1.studentid AND sc1.courseid = (SELECT courseid FROM courseinfo WHERE coursename = '语文')
INNER JOIN scoreinfo AS sc2
ON s.studentid = sc2.studentid AND sc2.courseid = (SELECT courseid FROM courseinfo WHERE coursename = '数学'); -- 16、查询个人成绩中每门功课都不及格的学生信息
-- 可能性1、无成绩的也算满足条件
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid NOT IN
(
SELECT studentid
FROM scoreinfo
WHERE score >= 60
);
-- 可能性2、无成绩的不算满足条件
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid IN
(
-- 如下写法不正确:因为这样会把部分课程不及格部分课程及格的同学也筛选出来
-- SELECT studentid
-- FROM scoreinfo
-- WHERE score < 60 -- 正确写法:按照学生编号分组,分组后组里最高的课程分数还小于60分,意味着所有课程都不及格
SELECT studentid
FROM scoreinfo
GROUP BY studentid
HAVING MAX(score) < 60
); -- 17、查询每门功课的分数段人数,显示为:课程编号、课程名称、选课人数、[优秀90~100]、[良好80~90]、[一般70~80]、[及格60~70]、[不及格0~60]
SELECT
sc.`courseid` AS 课程编号,
c.`coursename` AS 课程名称,
COUNT(sc.`studentid`) AS 选课人数,
SUM(CASE WHEN sc.score >= 90 AND sc.score <= 100 THEN 1 ELSE 0 END) AS `[优秀90~100]`,
SUM(CASE WHEN sc.score >= 80 AND sc.score < 90 THEN 1 ELSE 0 END) AS `[良好80~90]`,
SUM(CASE WHEN sc.score >= 70 AND sc.score < 80 THEN 1 ELSE 0 END) AS `[一般70~80]`,
SUM(CASE WHEN sc.score >= 60 AND sc.score < 70 THEN 1 ELSE 0 END) AS `[及格60~70]`,
SUM(CASE WHEN sc.score >= 0 AND sc.score < 60 THEN 1 ELSE 0 END) AS `[不及格0~60]`
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c ON sc.`courseid` = c.`courseid`
GROUP BY sc.`courseid`; -- 18、查询没有选修全部课程的学生信息
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid IN
(
-- 按照学生编号分组,每组中的课程统计数量小于课程信息表中课程数量的就是没有选修全部课程的学生
SELECT studentid
FROM scoreinfo
GROUP BY studentid
HAVING COUNT(courseid) < (SELECT COUNT(courseid) FROM courseinfo)
); -- 19、查询和刘备(学生编号1)至少一起选修了一门课程的学生编号和学生姓名
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid IN
(
-- 至少和刘备一起选修了一门课程
SELECT studentid
FROM scoreinfo
WHERE courseid IN
(
-- 查询出刘备选的课程
SELECT courseid
FROM scoreinfo AS sc
INNER JOIN studentinfo AS s
ON s.`studentid` = sc.`studentid` AND s.`studentid` = 1 AND s.`studentname` = '刘备'
)
); -- 20、查询和张飞(学生编号3)选修的课程完全相同的学生编号和学生姓名
-- 思路:
-- 1)首先制作两个成绩信息表的连接,右表为张飞(学生编号3)的课程及成绩
-- 此时会得到 完全和张飞课程相同的同学 和 部分和张飞课程相同的同学
SELECT *
FROM scoreinfo AS sc1
INNER JOIN scoreinfo AS sc2 ON sc1.`courseid` = sc2.`courseid` AND sc2.`studentid` = 3 AND sc1.`studentid` <> sc2.`studentid`
-- 2)在此基础上,在新生成的集合中按照学生编号进行分组,如果有学生的课程数量和张飞的课程数量一致的,那就张飞(学生编号3)选修的课程完全相同的学生
SELECT s.`studentid` AS 学生编号, s.`studentname` AS 学生姓名, s.`studentgender` AS 学生性别, s.`studentage` AS 学生年龄
FROM studentinfo AS s
WHERE s.studentid IN
(
SELECT sc1.`studentid`
FROM scoreinfo AS sc1
INNER JOIN scoreinfo AS sc2 ON sc1.`courseid` = sc2.`courseid` AND sc2.`studentid` = 3 AND sc1.`studentid` <> sc2.`studentid`
GROUP BY sc1.`studentid`, sc2.`studentid`
HAVING COUNT(sc1.`courseid`) = (SELECT COUNT(courseid) FROM scoreinfo WHERE studentid = 3)
); -- 21、按个人平均成绩降序排列显示学生的语文、数学、英语三门功课的成绩(选修了几门计算几门的平均分,未选修的课程显示未选)
-- 显示为:学生编号、学生姓名、平均成绩、语文成绩、数学成绩、英语成绩
SELECT
sc.`studentid` AS 学生编号,
s.`studentname` AS 学生姓名,
AVG(sc.`score`) AS 平均成绩,
IFNULL((
SELECT sc1.score
FROM scoreinfo AS sc1
WHERE sc1.studentid = sc.`studentid`
AND sc1.courseid = (SELECT courseid FROM courseinfo WHERE coursename = '语文'))
, '未选') AS 语文成绩,
IFNULL((
SELECT sc2.score
FROM scoreinfo AS sc2
WHERE sc2.studentid = sc.`studentid`
AND sc2.courseid = (SELECT courseid FROM courseinfo WHERE coursename = '数学'))
, '未选') AS 数学成绩,
IFNULL((
SELECT sc3.score
FROM scoreinfo AS sc3
WHERE sc3.studentid = sc.`studentid`
AND sc3.courseid = (SELECT courseid FROM courseinfo WHERE coursename = '英语'))
, '未选') AS 英语成绩
FROM scoreinfo AS sc
INNER JOIN studentinfo AS s
ON sc.`studentid` = s.`studentid`
GROUP BY sc.`studentid`
-- order by AVG(sc.`score`) desc;
-- 上面写法和下面写法均可,因为ORDER BY子句在SELECT子句之后执行的
ORDER BY 平均成绩 DESC; -- 22、查询每门功课的最高分和最低分,显示为:课程编号、课程名称、最高分、最低分
SELECT
sc.courseid AS 课程编号,
c.`coursename` AS 课程名称,
MAX(sc.`score`) AS 最高分,
MIN(sc.`score`) AS 最低分
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c
ON sc.courseid = c.courseid
GROUP BY sc.courseid; -- 23、查询只选修了一门课程的学生的学生编号和学生姓名
SELECT
sc.`studentid` AS 学生编号,
s.`studentname` AS 学生姓名
FROM scoreinfo AS sc
INNER JOIN studentinfo AS s
ON sc.studentid = s.studentid
GROUP BY sc.studentid
HAVING COUNT(sc.courseid) = 1; -- 24、查询学过张老师教的全部课程的学生的学生编号和学生姓名
SELECT
sc.`studentid` AS 学生编号,
s.`studentname` AS 学生姓名
FROM scoreinfo AS sc
INNER JOIN courseinfo AS c ON sc.courseid = c.courseid
INNER JOIN teacherinfo AS t ON c.teacherid = t.teacherid AND t.teachername = '张老师'
INNER JOIN studentinfo AS s ON sc.studentid = s.studentid
GROUP BY sc.studentid
HAVING COUNT(sc.courseid) = (
-- 张老师教的课程数量
SELECT COUNT(courseinfo.`courseid`)
FROM courseinfo
INNER JOIN teacherinfo AS t ON courseinfo.teacherid = t.teacherid AND t.teachername = '张老师'
); -- 25、学生信息表中被人删除了若干条记录,现在需要查询出第4行至第6行的记录来使用(考虑使用多种实现方式,提示:使用LIMIT 和 不使用LIMIT)
-- delete from studentinfo where studentid = 3 or studentid = 7; -- 写法1、直接使用LIMIT关键字
SELECT * FROM studentinfo LIMIT 3, 3; -- 写法2、考虑取出前6行,进行倒序排列,再取出前3行,再倒序
SELECT *
FROM
(
SELECT *
FROM
(
SELECT *
FROM (SELECT * FROM studentinfo LIMIT 0, 6) AS temp1
ORDER BY temp1.studentid DESC
) AS temp2 LIMIT 0, 3
) AS temp3
ORDER BY temp3.studentid ASC; -- 写法3、不使用LIMIT关键字
SELECT temp.`studentid` AS 学生编号, temp.`studentname` AS 学生姓名, temp.`studentgender` AS 学生性别, temp.`studentage` AS 学生年龄
FROM
(
SELECT
*,
(SELECT COUNT(*) FROM studentinfo AS s2 WHERE s2.studentid <= s1.`studentid`) AS rownum
FROM studentinfo AS s1
) AS temp
WHERE temp.rownum BETWEEN 4 AND 6;

mysql<六>的更多相关文章

  1. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  2. mysql每秒最多能插入多少条数据 ? 死磕性能压测

    前段时间搞优化,最后瓶颈发现都在数据库单点上. 问DBA,给我的写入答案是在1W(机械硬盘)左右. 联想起前几天infoQ上一篇文章说他们最好的硬件写入速度在2W后也无法提高(SSD硬盘) 但这东西感 ...

  3. LINUX篇,设置MYSQL远程访问实用版

    每次设置root和远程访问都容易出现问题, 总结了个通用方法, 关键在于实用 step1: # mysql -u root mysql mysql> Grant all privileges o ...

  4. nodejs进阶(6)—连接MySQL数据库

    1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...

  5. MySQL高级知识- MySQL的架构介绍

    [TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...

  6. 闰秒导致MySQL服务器的CPU sys过高

    今天,有个哥们碰到一个问题,他有一个从库,只要是启动MySQL,CPU使用率就非常高,其中sys占比也比较高,具体可见下图. 注意:他的生产环境是物理机,单个CPU,4个Core. 于是,他抓取了CP ...

  7. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  8. Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制

    将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...

  9. Docker笔记一:基于Docker容器构建并运行 nginx + php + mysql ( mariadb ) 服务环境

    首先为什么要自己编写Dockerfile来构建 nginx.php.mariadb这三个镜像呢?一是希望更深入了解Dockerfile的使用,也就能初步了解docker镜像是如何被构建的:二是希望将来 ...

  10. 当忘记mysql数据库密码时如何进行修改

    因为长时间没有使用数据库了,或者把密码改完之后就忘了数据库密码,不能正常进入数据库,也无法修改密码,有一个简单的常用修改密码方式: 1.首先找到和打开mysql.exe和mysqld.exe所在的文件 ...

随机推荐

  1. ROS自动切换策略

    自动切换策略,具体如下 监视地址:1.1.1.1 轮询时间:30s:超时时间:1000ms up /ip firewall nat set [/ip firewall nat find comment ...

  2. HDU 1160 FatMouse's Speed (动态规划、最长下降子序列)

    FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  3. HDU 1263 水果 (STL map)

    水果 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...

  4. [Python3] 027 常用模块 time

    目录 time 1. 时间戳 2. UTC 时间 3. 夏令时 4. 时间元组 5. 举例 5.1 例子1 例子2 例子3 例子4 例子5 例子6 例子7 time 1. 时间戳 一个时间表示,根据不 ...

  5. http请求跨域问题分析

    http请求跨域问题分析 个人认为可能涉及很多http的知识,本人才疏学浅不敢妄自揣测,只是做个笔记为了以后对比理解,从原生fetch说起吧,前提假设有个后端服务,我用express来模拟,如下: v ...

  6. 初步学习jquery学习笔记(一)

    什么是jquery? Jquery是javascript的一个函数库包含以下功能: html元素选取 html元素的操作 css操作 html事件的函数 javacript的特效 html的遍历和修改 ...

  7. 关于setter 和 getter方法的一些总结(初级)

    1.最基础的set 和 get 准备工作 Person.h @interface Person : NSObject { NSString *_hobby; // ObjC建议成员变量带"_ ...

  8. 字典树(trie树) 后缀树 广义后缀树

    转自:http://www.cnblogs.com/dong008259/archive/2011/11/11/2244900.html (1)字典树(Trie树) Trie是个简单但实用的数据结构, ...

  9. 用Kindle阅读PDF最简单的3个方法!

    老实说,Kindle 对于PDF文件是很不友好的,经常会出现各种排版问题,所以,对电子阅读器方面比较了解的同学都知道,如果需要经常用阅读器查看PDF文件的话,最好还是买一款更大屏幕的设备,而Kindl ...

  10. 32、出任爬虫公司CEO(爬取职友网招聘信息)

    职友集,搜索到全国上百家招聘网站的最新职位.   https://www.jobui.com/rank/company/   打开网址后,你会发现:这是职友集网站的地区企业排行榜,里面含有     本 ...