sql

(1)找出连续7天登陆,连续30天登陆的用户(小红书笔试,电信云面试),最大连续登陆天数的问题 --窗口函数 

(2)求连续点击三次的用户数,中间不能有别人的点击 ,最大连续天数的变形问题(腾讯微保面试)--窗口函数

(3)计算除去部门最高工资,和最低工资的平均工资(字节跳动面试)--窗口函数

(4)留存的计算,和累计求和的计算 --窗口函数,自联结(pdd面试)

(5)AB球队得分流水表,得到连续三次得分的队员名字 和每次赶超对手的球员名字,(pdd面试)


把这几类题型吃透,再也不怕手撕SQL和笔试了,其中最难的是题(5),整个面试的sql基本上都是窗口函数的玩法,搭配case when 也考得比较多。

(1) 找出连续7天登陆,连续30天登陆的用户

select *
from
(
  select user_id ,count(1) as num
  from
     (select user_id,date_sub(log_in_date, rank) dts
     from    (select user_id,log_in_date,	
                  row_number() over(partitioned by user_id order by log_in_date ) as	rank
		  from user_log
	   )t
      )a
  group by dts
)b
where num = 7  

计算连续登陆最大天数_bigdataprimary的博客-CSDN博客​blog.csdn.net

(2)求连续点击三次的用户数,而且中间不能有别人的点击,

a表记录了点击的流水信息,包括用户id ,和点击时间

usr_id a a b a a a a

click_time t1 t2 t3 t4 t5 t6 t7 

row_number() over(order by click_time) as rank_1 得到rank_1为 1 2 3 4 5 6 7 

row_number() over(partition by usr_id order by click_time) 得到rank_2 为 1 2 1 3 4 5 6 

rank_1- rank2 得到diff 为 0 0 2 1 1 1 1 

这时我们发现只需要对diff进行分组计数大于3个就是连续点击大于三且中间没有其他人点击的用户

select distinct usrid
from    
(
   select *, rank_1- rank2  as diff
   from
  (
      select *,
      row_number() over(order by click_time) as  rank_1
      row_number() over(partition by usr_id order by click_time) as rank_2
      from a
   ) b
) c
group by diff,usr_id
having count(diff) >=3

(3)计算除去部门最高工资,和最低工资的平均工资(字节跳动面试)--窗口函数

emp 表 

id 员工 id ,deptno 部门编号,salary 工资

核心是使用窗口函数降序和升序分别排一遍就取出了最高和最低。

select a.deptno,avg(a.salary)
from  
 (
 select *, rank() over( partition by deptno order by salary ) as rank_1
 , rank() over( partition by deptno order by salary desc) as rank_2 
 from emp
 )  a 
group by a.deptno
where a.rank_1 >1 and a.rank_2 >1 

(4) 留存的计算,和累计求和的计算 --窗口函数,自联结(pdd面试)

累计求和问题,使用sum() 窗口函数
留存计算   绚丽的小海螺:SQL 计算留存率-链家面试题

(5)AB球队得分流水表,得到连续三次得分的队员名字 和每次赶超对手的球员名字(pdd)

在复盘时发现有类似原题,这是我在面试中遇到的最难的题

问题:两支篮球队进行了激烈的篮球比赛,比分交替上升。比赛结束后,你有一张两队得分分数的明细表,记录了球队team,球员号码number,球员姓名name, 得分分数score 以及得分时间scoretime(datetime)。现在球队要对比赛中表现突出的球员做出嘉奖,所以请你用sql统计出

1)连续三次(及以上)为球队得分的球员名单

2)比赛中帮助各自球队反超比分的球员姓名以及对应时间。

先建一个类似的表

CREATE TABLE basketball_game_score_detail(
   team  VARCHAR(40) NOT NULL ,
   number VARCHAR(100) NOT NULL,
   score_time datetime NOT NULL,
   score int NOT NULL,
   name varchar(100)  NOT NULL
);
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:01:14',1,'A1');
insert into  basketball_game_score_detail values('A',5,'2020/8/28 9:02:28',1,'A5');
insert into  basketball_game_score_detail values('B',4,'2020/8/28 9:03:42',3,'B4');
insert into  basketball_game_score_detail values('A',4,'2020/8/28 9:04:55',3,'A4');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:06:09',3,'B1');
insert into  basketball_game_score_detail values('A',3,'2020/8/28 9:07:23',3,'A3');
insert into  basketball_game_score_detail values('A',4,'2020/8/28 9:08:37',3,'A4');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:09:51',2,'B1');
insert into  basketball_game_score_detail values('B',2,'2020/8/28 9:11:05',2,'B2');
insert into  basketball_game_score_detail values('B',4,'2020/8/28 9:12:18',1,'B4');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:13:32',2,'A1');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:14:46',1,'A1');
insert into  basketball_game_score_detail values('A',4,'2020/8/28 9:16:00',1,'A4');
insert into  basketball_game_score_detail values('B',3,'2020/8/28 9:17:14',3,'B3');
insert into  basketball_game_score_detail values('B',2,'2020/8/28 9:18:28',3,'B2');
insert into  basketball_game_score_detail values('A',2,'2020/8/28 9:19:42',3,'A2');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:20:55',1,'A1');
insert into  basketball_game_score_detail values('B',3,'2020/8/28 9:22:09',2,'B3');
insert into  basketball_game_score_detail values('B',3,'2020/8/28 9:23:23',3,'B3');
insert into  basketball_game_score_detail values('A',5,'2020/8/28 9:24:37',2,'A5');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:25:51',3,'B1');
insert into  basketball_game_score_detail values('B',2,'2020/8/28 9:27:05',1,'B2');
insert into  basketball_game_score_detail values('A',3,'2020/8/28 9:28:18',1,'A3');
insert into  basketball_game_score_detail values('B',4,'2020/8/28 9:29:32',1,'B4');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:30:46',3,'A1');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:32:00',1,'B1');
insert into  basketball_game_score_detail values('A',4,'2020/8/28 9:33:14',2,'A4');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:34:28',1,'B1');
insert into  basketball_game_score_detail values('B',5,'2020/8/28 9:35:42',2,'B5');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:36:55',1,'A1');
insert into  basketball_game_score_detail values('B',1,'2020/8/28 9:38:09',3,'B1');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:39:23',3,'A1');
insert into  basketball_game_score_detail values('B',2,'2020/8/28 9:40:37',3,'B2');
insert into  basketball_game_score_detail values('A',3,'2020/8/28 9:41:51',3,'A3');
insert into  basketball_game_score_detail values('A',1,'2020/8/28 9:43:05',2,'A1');
insert into  basketball_game_score_detail values('B',3,'2020/8/28 9:44:18',3,'B3');
insert into  basketball_game_score_detail values('A',5,'2020/8/28 9:45:32',2,'A5');
insert into  basketball_game_score_detail values('B',5,'2020/8/28 9:46:46',3,'B5');

这里我使用了lead和lag来取每个组的前几个值,这个和最大联系天数不太一样,但也可以用类似思路去解,但是使用lead和lag做起来更容易理解

select distinct a.name ,a.team from
(
select *,lead(name,1) over(partition by team order by score_time) as ld1
,lead(name,2) over(partition by team order by score_time) as ld2
,lag(name,1) over(partition by team order by score_time) as lg1
,lag(name,2) over(partition by team order by score_time) as lg2
from table
) a
where (a.name =a.ld1 and a.name =a.ld2)
or (a.name =a.ld1 and a.name =a.lg1)
or (a.name=a.lg1 and a.name=a.lg2)

第二小问面试时没完全做出来,说了下思路,现在想了想当时的思路还是有问题,而且这个题也并不难,核心还是记录每个时刻的累计得分表

SELECT TEAM,number,name,score_time,score,case when team='A' then score else 0 end as A_score
,case when team='B' then score else 0 end B_score
FROM basketball_game_score_detail
ORDER BY SCORE_time

如下得到每个时刻的累计得分表

select team,number,name,score_time,A_score,b_score
,sum(A_score)over(order by score_time) as  a_sum_score2
,sum(b_score)over(order by score_time) as b_sum_score2
from 
(
  SELECT TEAM,number,name,score_time,score,case when team='A' then score else 0 end as A_score
  ,case when team='B' then score else 0 end B_score
  FROM basketball_game_score_detail
  ORDER BY SCORE_time
) as x

 

计算每个时刻的累计得分差,和上个时间的累计得分差,只要两个的符号相反就是反超时刻。感觉思路还是比较简洁的。

select *,score_gap*last_score_gap
from 
(
	select  *,a_sum_score2-b_sum_score2 as score_gap 
	,lag(a_sum_score2-b_sum_score2,1)over(order by score_time) as last_score_gap
	from 
	(
		select team,number,name,score_time,A_score,b_score
		,sum(A_score)over(order by score_time) as  a_sum_score2
		,sum(b_score)over(order by score_time) as b_sum_score2
		from (
			SELECT TEAM,number,name,score_time,score,case when team='A' then score else 0 end as A_score
			,case when team='B' then score else 0 end B_score
			FROM basketball_game_score_detail
			ORDER BY SCORE_time
		) as x
	) as y
) as z
where z.score_gap*last_score_gap<=0
and a_sum_score2<>b_sum_score2 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define MAX_NAME_LEN 20 int main() { char name[MAX_NAME_LEN]; int n, i, j, k; printf("请输入人数:"); scanf("%d", &n); char **groupA = (char **)malloc(n * sizeof(char *)); char **groupB = (char **)malloc(n * sizeof(char *)); for (i = 0; i < n; i++) { groupA[i] = (char *)malloc(MAX_NAME_LEN * sizeof(char)); groupB[i] = (char *)malloc(MAX_NAME_LEN * sizeof(char)); } printf("请输入每个人的名字:\n"); for (i = 0; i < n; i++) { scanf("%s", name); strcpy(groupA[i], name); } srand(time(NULL)); // 初始化随机数生成器 for (i = 0; i < n; i++) { j = rand() % n; // 随机分组 if (groupB[j][0] == '\0') { // 如果groupB[j]还没有分到人 strcpy(groupB[j], groupA[i]); // 把groupA[i]分到groupB[j] } else { // 如果groupB[j]已经分到了人 // 找到下一个没有分到人的位置 for (k = j + 1; k != j; k++) { if (k == n) k = 0; if (groupB[k][0] == '\0') { strcpy(groupB[k], groupA[i]); break; } } } } printf("A组:\n"); for (i = 0; i < n; i++) { printf("%s\n", groupA[i]); } printf("B组:\n"); for (i = 0; i < n; i++) { printf("%s\n", groupB[i]); } for (i = 0; i < n; i++) { free(groupA[i]); free(groupB[i]); } free(groupA); free(groupB); return 0; } ``` 说明: 1. 首先,根据人数 n,动态分配两个二维字符数组 groupA 和 groupB。groupA 用来存储输入的名字,groupB 用来存储随机分组后的结果。 2. 从标准输入中读取每个人的名字,并将其存储到 groupA 数组中。 3. 使用 srand(time(NULL)) 初始化随机数生成器,然后使用 rand() 函数生成一个 0 到 n-1 之间的随机整数 j,将 groupA[i] 分到 groupB[j] 中。如果 groupB[j] 已经存储了一个名字,则寻找下一个没有存储名字的位置,直到找到一个位置可以存储 groupA[i]。 4. 最后,输出分组结果,并释放动态分配的内存。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值