SQL

200 阅读2分钟

1.窗口函数(排名)

<窗口函数> over (partition by <用于分组的列名>
                order by <用于排序的列名>)

1)每个班级内:按班级分组

partition by用来对表分组。在这个例子中,所以我们指定了按“班级”分组(partition by 班级)
2)按成绩排名

order by子句的功能是对分组后的结果进行排序,默认是按照升序(asc)排列。在本例中(order by 成绩 desc)是按成绩这一列排序,加了desc关键词表示降序排列。

通过下图,我们就可以理解partiition by(分组)和order by(在组内排序)的作用了。

image.png

窗口函数具备了我们之前学过的group by子句分组的功能和order by子句排序的功能。那么,为什么还要用窗口函数呢?

这是因为,group by分组汇总后改变了表的行数,一行只有一个类别。而partiition by和rank函数不会减少原表中的行数

select *,
   rank() over (order by 成绩 desc) as ranking,
   dense_rank() over (order by 成绩 desc) as dese_rank,
   row_number() over (order by 成绩 desc) as row_num
from 班级表

image.png

rank函数:这个例子中是5位,5位,5位,8位,也就是如果有并列名次的行,会占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,4。

dense_rank函数:这个例子中是5位,5位,5位,6位,也就是如果有并列名次的行,不占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,2。

row_number函数:这个例子中是5位,6位,7位,8位,也就是不考虑并列名次的情况。比如前3名是并列的名次,排名是正常的1,2,3,4。

参考通俗易懂的学会:SQL窗口函数 - 知乎 (zhihu.com)

-- 23、使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称(重点和18题类似)
select s.c_id,c.c_name,
sum(case when s.s_score <= 100 and s.s_score > 85 then 1 else 0 end),
sum(case when s.s_score <= 85 and s.s_score > 70 then 1 else 0 end),
sum(case when s.s_score <= 72 and s.s_score > 60 then 1 else 0 end),
sum(case when s.s_score <= 60 then 1 else 0 end)
from score s inner join course c on s.c_id = c.c_id group by s.c_id,c.c_name

-- 24、查询学生平均成绩及其名次(同19题,重点)
select s_id,avg(s_score),ROW_NUMBER() over(order by avg(s_score) desc) from score group by s_id  

-- 26、查询每门课程被选修的学生数(不重点)

select c.c_id,c.c_name,count(distinct s.s_id) from score s inner join course c on s.c_id = c.c_id
group by c.c_id,c.c_name;

-- 27、 查询出只有两门课程的全部学生的学号和姓名(不重点)
select s.s_id,s.s_name from student s inner join score sc on s.s_id = sc.s_id group by s.s_id having count(c_id) = 2

-- 31、查询1990年出生的学生名单(重点year)
-- year month 支持 yyyy-mm-dd yyyymmdd yyyy/mm/dd等格式
select * from student where YEAR(s_birth) = 1990

-- 36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数(重点)
select st.s_name,s_name,c.c_name,s.s_score from score as s 
inner join course as c on s.c_id = c.c_id 
inner join student as st on s.s_id = st.s_id
where s.s_score > 70

SQL219 获取员工其当前的薪水比其manager当前薪水还高的相关信息

思路:如果需要把一个表两行数据合并为一行。再无法用group by的情况下。我们可以进行join两次需要的表,一次对应一个数据。两次就能把它合成一个数据了。

select a.emp_no,b.emp_no ,c.salary,d.salary
  from dept_emp a inner join
       dept_manager b on a.dept_no = b.dept_no inner join 
       salaries c on a.emp_no = c.emp_no inner join 
       salaries d on b.emp_no = d.emp_no
 where c.salary > d.salary      

思路2:把员工和经理的分别查出来,然后链表

select a.emp_no,b.emp_no,a.ems,b.ms from
# 员工
(select d.emp_no,s.salary ems,d.dept_no emd  from dept_emp d inner join salaries s on d.emp_no  = s.emp_no where d.emp_no not in(select emp_no from dept_manager)) as a
inner join
# 经理
(select d.emp_no,s.salary ms,d.dept_no md  from dept_manager d inner join salaries s on d.emp_no  = s.emp_no ) as b
on a.emd = b.md
where a.ems > b.ms