【SQL屠夫系列】- SQL高频面试之计算累加报表,还不会你来K我

在这里插入图片描述


1. 前言

在如今的程序员面试过程中,考察SQL部分能力,虽不是难点,但几乎是必考.
为检查思路盲点,避免翻船,各位看官也可以复盘下,如对你有一丝的帮助,欢迎给个赞叭~
ps: 数据开发者,建议可以自己加难度进行考察

难度:中等
面试频率:高

2. 常见题型

  • 请通过sql语句实现数量累加查询
  • 请通过sql语句计算企业每月累计发放员工薪资
  • 请通过sql语句计算企业累计的出货量
  • 请通过sql实现每月各渠道用户注册数
  • 请通过sql计算xxx数值的累计/累加值

一般就是这种指定时间周期去累积计算某个对象分组的业务指标累计值

3. 前置准备

3.1 表DDL

-- hive
create table user_code_info(username string,dt string,codeNum int)
row format delimited fields terminated by ',';


-- postgres
CREATE SEQUENCE IF NOT EXISTS test.user_code_info_seq;
CREATE TABLE user_code_info (
  id numeric(20) NOT NULL DEFAULT nextval('test.user_code_info_seq'::regclass), -- 主键id
  username varchar(32) NOT NULL, -- 姓名
  dt varchar(32) NOT NULL, -- 日期
  code_num numeric(20) NULL, -- 代码量
  CONSTRAINT user_code_info_pkey PRIMARY KEY (id)
);

3.2 mock数据

'马云', '20220101', 2000 
'马云', '20220115', 2000
'马云', '20220218', 2000
'马云', '20220311', 2000
'李彦宏', '20220101', 2000
'李彦宏', '20220201', 2000
'李彦宏', '20220301', 2000
'李彦宏', '20220401', 2000
'马化腾', '20220701', 2000
'马化腾', '20220801', 2000
'马化腾', '20220910', 2000

3.3 同步到表

-- hive
load data local inpath '/home/hadoop/user_code_info.txt' into table user_code_info;

-- postgres
INSERT INTO test.user_code_info_seq (username, dt, code_num)
VALUES ('马云', '20220101', 2000), 
('马云', '20220115', 2000),
('马云', '20220218', 2000),
('马云', '20220311', 2000),
('李彦宏', '20220101', 2000),
('李彦宏', '20220201', 2000),
('李彦宏', '20220301', 2000),
('李彦宏', '20220401', 2000),
('马化腾', '20220701', 2000),
('马化腾', '20220801', 2000),
('马化腾', '20220910', 2000),
;

在这里插入图片描述

4. 面试案例

4.1 需求

求user_code_info表中每位员工月度累积代码量(当月要累计到之前的月份)

4.2 答题

step 1 求每月每个用户写的代码量

select b1.username, b1.dt_m, sum(b1.code_num) as num_m
from
(
	select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
	from 
		test.user_code_info a1
) b1
group by username, dt_m

在这里插入图片描述

step 2 自己关联自己找出比自己小的月份记录

select c1.username a_username, c1.dt_m a_dt_m,c1.num_m a_num_m,
	c2.username b_username, c2.dt_m b_dt_m, c2.num_m
FROM
(
	select b1.username, b1.dt_m, sum(b1.code_num) as num_m
	from
	(
		select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
		from 
			test.user_code_info a1
	) b1
	group by username, dt_m
) c1
left join

(
	select b1.username, b1.dt_m, sum(b1.code_num) as num_m
	from
	(
		select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
		from 
			test.user_code_info a1
	) b1
	group by username, dt_m
) c2
on c1.username = c2.username and c1.dt_m>=c2.dt_m

在这里插入图片描述

step3 累计比自己小的月份

就在step2的基础上改下即可

select c1.username, c1.dt_m, sum(c2.num_m) as code_num_m
FROM
(
	select b1.username, b1.dt_m, sum(b1.code_num) as num_m
	from
	(
		select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
		from 
			test.user_code_info a1
	) b1
	group by username, dt_m
) c1
left join

(
	select b1.username, b1.dt_m, sum(b1.code_num) as num_m
	from
	(
		select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
		from 
			test.user_code_info a1
	) b1
	group by username, dt_m
) c2
on c1.username = c2.username and c1.dt_m >= c2.dt_m
group by c1.username, c1.dt_m
order by c1.dt_m

4.3 其他解法

思路有了,解法很灵活
最简单的就是使用开窗函数直接进行分组

可以借鉴
【SQL屠夫系列】leetcode-180. 连续出现的数字-(实战扩展:连续登陆N天)

4.3.1 开窗函数法

开窗函数用的多了,很自然的分组求和的问题会自然想到使用 SUM OVER()去统计
sql简单明了:

select username, dt_m, code_num, SUM(code_num) OVER(partition by username ORDER BY dt_m)
from
(
	select username, to_char(to_date(dt, 'YYYYMMdd'),'YYYYMM') dt_m, code_num 
	from 
		test.user_code_info a1
) b1 order by dt_m

在这里插入图片描述

拓展

你还有其他解法思路吗?可以动手试一试


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_31557939/article/details/126892295