qidao123.com技术社区-IT企服评测·应用市场

标题: 头歌openGauss数据库-实验2-5-复杂查询(紧张!!!) [打印本页]

作者: 羊蹓狼    时间: 2025-5-1 20:40
标题: 头歌openGauss数据库-实验2-5-复杂查询(紧张!!!)
概要:

        文章主要围绕 SQL 相关知识展开,先介绍了 JOINLEFT JOIN 的区别及各自应用场景,接着阐述了窗口函数的定义、语法、类型、子句作用及应用场景,还提及了 CASE IF 的使用。随后通过分数排名、体育馆人流量高峰期查询、统计总成绩等十个具体应用场景的 SQL 查询示例,详细讲解了怎样运用各类 SQL 函数、语句及操作来实现差别的查询需求,包罗排名计算、数据筛选、聚合统计、值的互换以及座位调解等多种功能。
目录
JOIN与LEFT JOIN的区别
窗口函数:
CASE与IF的使用
第一关:分数排名
表明:
第二关:体育馆的人流量
 表明:
第三关:统计总成绩
第四关:查询学平生均分
 表明:
COALESCE函数
第五关:查询修课相同弟子信息
 表明:
第六关:查询各科成绩并排序
表明:
第七关:查询张老师课程成绩最高的弟子信息
 表明:
第八关:查询两门课程不合格同学信息
表明:
第九关:互换工资
表明:
第十关:换座位
 表明:

JOIN与LEFT JOIN的区别

窗口函数:

        先表明一下什么是窗口函数,后面会用到。
CASE与IF的使用

  1. SELECT
  2.     CASE                       ###如果
  3.     WHEN sex='1' THEN '男'     ###sex='1',则返回值'男'
  4.     WHEN sex='2' THEN '女'     ###sex='2',则返回值'女'  
  5.     ELSE '其他'     ###其他的返回'其他’
  6.     END                       ###结束
  7. FROM   sys_user     ###整体理解: 在sys_user表中如果sex='1',则返回值'男'如果sex='2',则返回值'女' 否则返回'其他’
复制代码

  1. SELECT IF(sex='1','男','女') AS sex FROM sys_user;     ###如果sex='1'则返回值'男' 否则返回值为'女'
复制代码
第一关:分数排名

编写SQL查询来实现二种排名方式的分数排名。
score表布局信息如下:


如果两个分数相同,则两个分数排名(Rank)相同。

 代码如下:
  1. SELECT Score,DENSE_RANK() OVER (ORDER BY Score DESC) AS rank
  2. FROM score;
  3. SELECT Score,RANK() OVER (ORDER BY Score DESC) AS rank
  4. FROM score;
复制代码
表明:


第二关:体育馆的人流量

某市建了一个新的体育馆,每日人流量信息被记录在gymnasium表中:序号 (id)、日期 (date)、 人流量 (visitors_flow)。
请编写一个查询语句,找出人流量的高峰期。高峰期时,至少连续三行记录中的人流量不少于100。
gymnasium表布局数据如下:

代码如下:
  1. SELECT DISTINCT g.id,g.date,g.visitors_flow
  2. FROM gymnasium g
  3.     JOIN gymnasium g2 ON g.id BETWEEN g2.id AND g2.id + 2
  4. WHERE(
  5.     SELECT COUNT(*)
  6.     FROM gymnasium g3
  7.     WHERE g3.id BETWEEN g2.id AND g2.id + 2
  8.     AND g3.visitors_flow >= 100
  9. ) >= 3
  10. ORDER BY g.id;
复制代码
 表明:


第三关:统计总成绩

计算每个班的语文总成绩和数学总成绩,要求科目中低于60分的成绩不记录总成绩。
tb_score布局数据:

tb_class表布局数据:

 代码如下:
  1. SELECT classname,
  2.     SUM(CASE WHEN chinese>=60 THEN chinese ELSE 0 END) chinese,
  3.     SUM(CASE WHEN maths>=60 THEN maths ELSE 0 END) maths
  4. FROM tb_score JOIN tb_class ON name = stuname
  5. GROUP BY classname;
复制代码
 这题比较简单,主要是使用SUM求和同时使用CASE判断一下成绩是否低于60分,如果低于60的话该成绩为设为0,如许就不会影响总成绩。
第四关:查询学平生均分

根据提供的表和数据,查询均匀成绩小于60分的同学的弟子编号(s_id)、弟子姓名(s_name)清静均成绩(avg_score),要求均匀成绩保留2位小数点。(留意:包罗有成绩的和无成绩的)
student表数据:

course表数据:

 teacher表数据:

 score表部分数据:

 代码如下:
  1. SELECT student.s_id,
  2.     student.s_name,
  3.     CASE WHEN ROUND(COALESCE(AVG(score.s_score),0),2) = 0
  4.          THEN ROUND(COALESCE(AVG(score.s_score),0),0)
  5.          ELSE ROUND(COALESCE(AVG(score.s_score),0),2)
  6.     END AS avg_score
  7. -- 需要保留成绩为null的数据,因此需要采用左连接,保存左边表的全部信息
  8. FROM student LEFT JOIN score ON student.s_id = score.s_id
  9. GROUP BY student.s_id,student.s_name
  10. HAVING avg_score<60
复制代码
 表明:

这个题目关键在于两个地方,第一:怎样让两个表连接之后生存为值为NULL的数据;第二:怎样处置惩罚值为NULL的数据。
第一个题目:使用开头提到的LEFT JOIN,如许会保留student表中的全部数据,如果一个弟子没有成绩的话,连接后score一栏会为NULL,被生存下来。如果只是使用JOIN的话,如果弟子没有成绩,那么该弟子不会保留在连接后的表中,导致丢失我们需要的数据。
第二个题目:使用COALESCE函数。
COALESCE函数

COALESCE函数可用于处置惩罚可能出现的 NULL 值情况。在 COALESCE(AVG(score.s_score),0) 中,它的参数是 AVG(score.s_score) 和 0。这里是先实验计算 score 表中每个弟子的均匀成绩(通过 AVG(score.s_score)),如果某个弟子在 score 表中没有成绩记录,那么 AVG(score.s_score)对于该弟子就会返回 NULL,然后接着检查下一个参数,发现是0,而不是NULL,那么0就被返回了,如许的话就相称与将NULL值更换为了0,如许就可以确保在后续计算均匀成绩时,纵然弟子没有成绩记录,也能到场到均匀成绩的计算中,只是其均匀成绩会被计算为0.
Tips:对于为什么有一个与0比较:因为末了的预期输出中只有0不保留小数位,因此把0作为一个特殊情况提出来
第五关:查询修课相同弟子信息

根据提供的表和数据,查询与s_id=01号同学学习的课程完全相同的其他同学的信息(学号s_id,姓名s_name,性别s_sex)。
student表数据:

course表数据:

 teacher表数据:

 score表部分数据:

 代码如下:
  1. WITH CourseList AS (
  2.     SELECT
  3.         c_id
  4.     FROM
  5.         score
  6.     WHERE
  7.         s_id = '01'
  8. )
  9. SELECT
  10.     s.s_id,
  11.     s.s_name,
  12.     s.s_sex
  13. FROM
  14.     student s
  15.     JOIN score sc ON s.s_id = sc.s_id
  16.     JOIN CourseList cl ON sc.c_id = cl.c_id
  17. GROUP BY
  18.     s.s_id,
  19.     s.s_name,
  20.     s.s_sex
  21. HAVING
  22.     COUNT(DISTINCT sc.c_id) = (SELECT COUNT(*) FROM CourseList)
  23.     AND s.s_id != '01'
  24. ORDER BY s.s_id DESC
复制代码
 表明:

1. 公共表表达式(CTE)部分:

2. 主查询部分

第六关:查询各科成绩并排序

根据提供的表和数据,查询各科成绩,进行排序并显示排名,按弟子编号(s_id)、课程编号(c_id)、弟子成绩(s_score)和排名(rank)进行输出,具体效果请查看测试集。
 student表数据:

course表数据:

 teacher表数据:

 score表部分数据:

代码如下:
  1. SELECT
  2.     sc.s_id,
  3.     sc.c_id,
  4.     sc.s_score,
  5.     DENSE_RANK() OVER (PARTITION BY sc.c_id ORDER BY sc.s_score DESC) AS rank
  6. FROM score sc
  7. ORDER BY sc.c_id,rank;
复制代码
表明:

        这里用到了上面提到的DENSE_RANK来进行排名 ,忘记的话可以到上面看一看,这里对c_id进行分组(预期输出按照c_id分组了)然后按照s_score降序排序末了得到rank值。
第七关:查询张老师课程成绩最高的弟子信息

根据提供的表和数据,查询选修“张三”老师所授课程的弟子中,成绩最高的弟子信息(具体输出信息请查看测试说明)及其成绩。
 student表数据:

course表数据:

 teacher表数据:

 score表部分数据:

代码如下:
  1. WITH ZSCourse AS (
  2.     SELECT c_id
  3.     FROM course
  4.     WHERE t_id = (
  5.         SELECT t_id
  6.         FROM teacher
  7.         WHERE t_name = '张三'
  8.     )
  9. )
  10. SELECT s.s_id,s.s_name,s.s_sex,sc.s_score,sc.c_id,c.c_name
  11. FROM student s
  12.     JOIN score sc ON s.s_id = sc.s_id
  13.     JOIN course c ON sc.c_id = c.c_id
  14.     JOIN ZSCourse zsc ON zsc.c_id = sc.c_id
  15. WHERE sc.s_score = (
  16.     SELECT MAX(sc1.s_score)
  17.     FROM score sc1
  18.     WHERE sc1.c_id = zsc.c_id
  19. )
复制代码
 表明:

1. 公共表表达式(CTE)部分

2. 主查询部分:

第八关:查询两门课程不合格同学信息

根据提供的表和数据,查询两门及其以上不合格课程的同学的学号(s_id)、姓名(s_name)及其均匀成绩(avg_score),要求计算均匀成绩后为整数。
  student表数据:

course表数据:

 teacher表数据:

 score表部分数据:

代码如下:
  1. SELECT s.s_id,s.s_name,ROUND(AVG(sc.s_score)) AS avg_score
  2. FROM student s JOIN score sc ON s.s_id = sc.s_id
  3. GROUP BY s.s_id,s.s_name
  4. HAVING(
  5.     SELECT COUNT(*)
  6.     FROM score sc2
  7.     WHERE sc2.s_score<60 AND sc2.s_id = s.s_id
  8. )>=2;
复制代码
表明:

这里就简单表明一下HAVING语句,相信前面的大家都能明确!
        HAVING语句中COUNT用于统计不合格的课程数,然后设置了两个统计的条件:第一:sc2.s_score<60用与筛选出小于60分的课程;第二: sc2.s_id = s.s_id用于保是针对当前分组(也就是当前弟子)的成绩记录进行统计。
第九关:互换工资

给定一张 tb_Salary 表,如下所示,有 m = 男性 和 f = 女性的值。互换全部的 f 和 m 值(例如,将全部 f 值更改为 m,反之亦然)。

要求只使用一句更新update语句,且不允许含有任何select语句完成任务。
 代码如下:
  1. UPDATE tb_Salary
  2. SET sex = CASE WHEN sex = 'f' THEN 'm' ELSE 'f' END;
复制代码
表明:

这题只要掌握了CASE或者IF的用法,便可以轻松办理,关于CASE和IF,在文章开头提到了,如果忘记的话可以回去看看。
第十关:换座位

小美是一所中学的信息科技老师,她有一张 tb_Seat座位表,寻常用来储存弟子名字和与他们相对应的座位 id。
tb_Seat表布局数据如下:

如今小美想改变相邻俩弟子的座位(若弟子人数为奇数,则无需改变末了一位同学的座位),如今需要你编写SQL输出小美想要的的效果。
代码如下:
  1. SELECT
  2.     CASE
  3.         WHEN id%2 = 1 AND id<(SELECT MAX(id) FROM tb_Seat) THEN id+1
  4.         WHEN id%2 = 0 AND id>1 THEN id-1
  5.         ELSE id
  6.     END
  7.     id,name
  8.     FROM tb_Seat
  9. ORDER BY id;
复制代码
 表明:

这题如果想要互换相邻弟子的姓名的话,可能不太好做,那么我们换一个思路,是不是可以互换id,然后按照id进行排序呢?如许是可以的,因为id是数值类型,可以通过加一或者减一的操作进行互换,比互换弟子的姓名就简单多了。那么这里我们也需要用到CASE语句,通过判断id是奇数还是偶数决定id是加一还是减一(奇数加一,偶数减一)就可以实现互换id的操作,然后还需要留意如果总人数为奇数的话末了一名弟子不互换,以是我们还需要比较id为奇数时该弟子是不是末了一名(第一个WHEN中的AND),如果时末了一名的话id保持不变(ELSE),末了按照id排序就可以了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4