数据库面试:开窗函数(敲详细解读,含大厂面试题sql经典题)

目录

目录

开窗函数的RANK语法

题目一:运行结果

题目二:运行结果

题目三:运行结果

开窗函数的SUM语法

题目四:运行结果

题目五:运行结果

题目六:运行结果



开窗函数的RANK语法

建表语句 学生成绩表

create table tb_score
(
    SNO     INT,
    SCLASS  INT,
    CHINESE INT,
    ENGLISH INT,
    ARITH   INT
);

INSERT INTO TB_SCORE
VALUES (1, 1, 83, 57, 73);
INSERT INTO TB_SCORE
VALUES (2, 1, 58, 76, 90);
INSERT INTO TB_SCORE
VALUES (3, 3, 89, 84, 96);
INSERT INTO TB_SCORE
VALUES (4, 2, 79, 86, 82);
INSERT INTO TB_SCORE
VALUES (5, 1, 58, 81, 93);
INSERT INTO TB_SCORE
VALUES (6, 1, 56, 90, 59);
INSERT INTO TB_SCORE
VALUES (7, 3, 77, 66, 77);
INSERT INTO TB_SCORE
VALUES (8, 2, 63, 56, 55);
INSERT INTO TB_SCORE
VALUES (9, 1, 91, 78, 91);
INSERT INTO TB_SCORE
VALUES (10, 3, 95, 81, 50);
# todo:开窗函数的排序语法
# todo  1.row_number() over(partition by xxx order by yyy)
# todo  1.1 partition by xxx 根据哪一列进行分堆,这个是可选参数
# todo  1.2 order by yyy 根据哪一列进行排序,这个是可选参数
# todo 不考虑并列  row_number()
# todo 考虑并列(按人头数)  rank()
# todo 考虑并列(按名次)  dense_rank()

# todo 目标1:先根据班级分堆 再根据语文成绩排序(倒序)
select sno,
       SCLASS,
       CHINESE,
       row_number() over (partition by SCLASS order by CHINESE desc ) as rn1_chinese,
       rank() over (partition by SCLASS order by CHINESE desc )       as rn2_chinese,
       dense_rank() over (partition by SCLASS order by CHINESE desc ) as rn3_chinese
from tb_score;

题目一:运行结果

# todo 目标2:先根据班级分堆 再根据语文成绩排序(倒序) 数学成绩 英语成绩 排序
select sno,
       sclass,
       chinese,
       english,
       arith,
       rank() over (partition by SCLASS order by CHINESE desc) rn1_chinese,
       rank() over (partition by SCLASS order by ENGLISH desc) rn2_english,
       rank() over (partition by SCLASS order by ARITH desc)   rn3_arith
from tb_score;

题目二:运行结果

# todo 目标3:想要每个班级语文成绩的前两名
# todo 知识点 sql执行顺序: from 1 where 2 group by 3 having 4 select 5 开窗函数 6
# todo 方式一 子查询
select*
from (select sno,
             sclass,
             chinese,
             english,
             arith,
             rank() over (partition by SCLASS order by CHINESE desc) rn1_chinese
      from tb_score) t1
where t1.rn1_chinese <= 2
order by SCLASS, rn1_chinese;

#todo 方式二
with t1 as (select sno,
                   sclass,
                   chinese,
                   english,
                   arith,
                   rank() over (partition by SCLASS order by CHINESE desc) rn1_chinese
            from tb_score)

select *
from t1
where rn1_chinese <= 2
order by SCLASS, CHINESE desc;

create table tb_user
(
    name  varchar(32),
    month varchar(32),
    amt   int
);

题目三:运行结果

开窗函数的SUM语法

建表语句  用户存款表

create table tb_user
(
    name  varchar(32),
    month varchar(32),
    amt   int
);

insert into tb_user
values ('张三', '01', 100);
insert into tb_user
values ('李四', '02', 120);
insert into tb_user
values ('王五', '03', 150);
insert into tb_user
values ('赵六', '04', 500);
insert into tb_user
values ('张三', '05', 400);
insert into tb_user
values ('李四', '06', 350);
insert into tb_user
values ('王五', '07', 180);
insert into tb_user
values ('赵六', '08', 400);
#todo 计算每个人的存款金额 排名 与占比
#todo round(xxx,2) 含义:让数字保留两位小数
#todo concat(xxx,yyy) 含义:让xxx和yyy 拼接到一起
select s.*,
       rank() over (order by s.personSum),
       concat(round((s.personSum / sum(s.personSum) over ()) * 100, 2), '%') as radio
from (select distinct name, sum(amt) over (partition by name ) as personSum from tb_user) s;
 

题目四:运行结果

建表语句

create table emp
(
    empno    varchar(32),
    ename    varchar(32),
    hiredate varchar(32),
    sal      int,
    dpetno   int
);

INSERT INTO emp VALUES
('7934', '刘备', '1982-01-23', 1300, 10),
('7844', '关羽', '1981-09-08', 1500, 10),
('7782', '张飞', '1981-06-09', 2450, 10),
('7839', '曹操', '1981-11-17', 5000, 10),
('7521', '张三', '1981-02-22', 1250, 20),
('7566', '李四', '1981-04-02', 2975, 20),
('7876', '王五', '1987-07-13', 1100, 20),
('7369', '赵六', '1980-12-17', 800, 20),
('7902', '孙悟空', '1981-12-03', 3000, 30),
('7499', '猪八戒', '1981-02-20', 1600, 30),
('7654', '沙和尚', '1981-09-28', 1250, 30),
('7900', '唐僧', '1981-12-03', 950, 30),
('7788', '杨过', '1987-07-13', 3000, 30),
('7698', '小龙女', '1981-05-01', 2850, 30);

with t1 as (select empno,
                   ename,
                   hiredate,
                   sal,
                   dpetno,
                   row_number() over (partition by dpetno order by sal desc ) as rn,
                   sum(sal) over (partition by dpetno)                        as sum_sal
            from emp)

select  ename,sal, dpetno, rn, round(sal / sum_sal, 2) as rate
from t1
where rn <= 3

题目五:运行结果

-- 问题: count(*) 和 count(1) 区别 占用空间区别 null不会被聚合函数统计
-- 如果没有partition by xxx 只有 order by 就会按照排序 进行累计求和
-- order by 默认范围:重头到尾 ,范围是可以改的
WITH
  t1 AS (
    SELECT SUBSTR(hiredate, 1, 4) AS year
    FROM emp
  ),
  t2 AS (
    SELECT t1.year, COUNT(*) AS cnt -- 这里应该是 COUNT(*) 而不是 COUNT(1),因为我们在分组
    FROM t1
    GROUP BY t1.year
  )
SELECT
  t2.year,
  t2.cnt,
  SUM(t2.cnt) OVER (ORDER BY t2.year) AS cnt2
FROM t2;

题目六:运行结果

  • 44
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值