拼多多和猿辅导SQL题
以下SQL為本人手寫,有些題目描述簡單可能存在歧義,歡迎探討交流
一.case專題-商品訂單數據
數據表:
訂單表orders,大概字段有(order_id’訂單號,'user_id‘用戶編號’, order_pay‘訂單金額’ ,
order_time‘下單時間’,‘商品一級類目commodity_level_1’,‘商品二級類目commodity_level_2’)
1. 求最近7天內每一個一級類目下成交總額排名前3的二級類目:
select commodity_level_1,commodity_level_2,total,r from(select *,row_number() over(partition by commodity_level_1 order by total desc) rfrom(select commodity_level_1,commodity_level_2,sum(order_by) totalfrom orders where timestampdiff(day,order_time,now()) <= 7 group by commodity_level_1,commodity_level_2) a)b where r<=3;2.提取8.1-8.10每一天消費金額排名在101-195的user_id
select order_date,user_id,total from(select *,row_number() over(partition by order_date,user_id order by total) rfrom(select convert(order_time,date) order_date,user_id,sum(order_by) totalfrom orderswhere convert(order_time,date) between '20190801' and '20190810'group by convert(order_time,date),user_id) a) b where r between 101 and 195二.case專題-活動運營數據分析
數據表
表1——訂單表orders,大概字段有(user_id‘用戶編號’, order_pay‘訂單金額’ , order_time‘下單時間’)
表2——活動報名表act_apply,大概字段有(act_id‘活動編號’,user_id‘報名用戶’,act_time‘報名時間’)
1.活動運營數據分析-統計每個活動對應所有用戶在報名后產生的總訂單金額,總訂單數
select a.user_id,sum(order_pay) total,count(*) num from orders o join act_apply a on o.user_id = a.user_id where o.order_time >= a.act_time group by a.act_id2.統計每個活動從開始后到當天(考試日)平均每天產生的訂單數,活動開始時間定義為最早有用戶報名的時間。(涉及到時間的數據類型均為:datetime)
select a.act_id,count(*)/timestampdiff(day,min(a.act_time),now()) from orders o join act_apply a on o.user_id = a.user_id where o.order_time >= a.act_time group by a.act_id三.case專題-用戶行為路徑分析
表1——用戶行為表tracking_log,大概字段有(user_id‘用戶編號’,opr_id‘操作編號’,log_time‘操作時間’)
1.統計每天符合以下條件的用戶數:A操作之后是B操作,AB操作必須相鄰
解題思路:運用窗口函數在每行數據生成一列數據:下次操作編號
注意要把datetime格式轉換成date格式來表示天
2.統計用戶行為序列為A-B-D的用戶數
其中:A-B之間可以有任何其他瀏覽記錄(如C,E等),B-D之間除了C記錄可以有任何其他瀏覽記錄(如A,E等)
select count(*) from(select user_id,group_concat(opr_id) ubpfrom tracking_loggroup by user_id) a where ubp like '%A%B%D%' and ubp not like '%A%B%C%D%'四.case專題-用戶留存分析
表1——用戶登陸表user_log,大概字段有(user_id‘用戶編號’,log_date‘登陸時間’)
1.求每天新增用戶數,以及他們第2天、30天的留存率
select count(distinct user_id),round(count(distinct case when datediff(log_date,fd)=1 then a.user_id else null end)/count(distinct user_id),2),round(count(distinct case when datediff(log_date,fd)=29 then a.user_id else null end)/count(distinct user_id),2) from user_log u left join (select user_id,min(log_date) fdfrom user_loggroup by user_id) a on u.user_id = a.user_id group by fd2.找近90天,30天,7天的登錄人數
select count(distinct case when datediff(curdate(),log_date)<=90 then user_id else null end),count(distinct case when datediff(curdate(),log_date)<=30 then user_id else null end),count(distinct case when datediff(curdate(),log_date)<=7 then user_id else null end) from user_log3.求用戶近一個月平均登錄時間間隔(按天)
select user_id,sum(datediff(log_date,l))/30 from(select user_id,log_date,lag(log_date,1) over(partition by user_id order by log_date) lfrom user_logwhere datediff(curdate(),log_date) <= 30group by user_id) a group by user_id五.case專題-統計特征(中位數,眾數,四分位數)
字段:店鋪id(shop_id),銷量(sale),商品id(commodity_id)
1.求每個店鋪商品銷量排名的中位數
select shop_id,avg(sale) from(select shop_id,commodity_id,sale,count(1) over(partition by shop_id) total,row_number() over(partition by shop_id order by sale desc) rfrom orders) a where abs(r-(total+1)/2)<1 group by shop_idabs(rn - (cnt+1)/2) < 1
解釋下上面的公式:
rn是給定長度為cnt的數列的序號排序,
eg:對于1,2,3,4,5,它的中位數所在序號是3,3-(5+1)/2 = 0
對于1,2,3,4,它的中位數所在序號是2,3
2 - (4+1)/2 = -0.5
3-(4+1)/2 = 0.5
可見(cnt+1)/2是一個數列的中間位置,如果是奇數數列,這個位置剛好是中位數所在
2.求每個店鋪訂購商品的眾數
select shop_id,commodity_id,mt from(select shop_id,commodity_id,total,max(total) over(partition by shop_id) mtfrom(select shop_id,commodity_id,count(*) as totalfrom ordersgroup by shop_id,commodity_id) a) b where total = mt3.求四分位數
三個表
T1:good_id,cate_id(分類)
T2:mall_id(店鋪), good_id
T3:mall_id, credit_score(信用分)
問,在不同分類中,店鋪的信用分前100和求top25%
六.case專題-GMV周同比統計
字段:時間(sale_date),店鋪類別(cate_id),店鋪數量(mall_num),gmv
1.拼多多618前后一周內各店鋪類別gmv的日均提升幅度和比例
注:以下解法只適用于數據連續情況,如果數據不連續,例如對于上一周沒有星期六,星期日的數據,lead(gmv,7)這樣規定移動窗口必然會出現錯誤。
select cate_id,avg(gmv-l),avg((gmv-l)/gmv) from(select sale_date,cate_id,mall_num,gmv,lag(gmv,7) over(partition by cate_id order by sale_date) lfrom T) a where sale_date between '20190611' and '20190625' group by cate_id2.在618前一周gmv top20%,20-40%等這5類商鋪在618后一周內gmv日均提升幅度和比例
注:寫的過程,分步一點點寫
select t3.cate_id,avg(l-gmv),avg((l-gmv)/gmv) from(select sale_date,cate_id,mall_num,gmv,lead(gmv,7) over(partition by cate_id order by sale_date) lfrom Twhere sale_date between '20190611' and '20190625') t3 join(select cate_id,case when r <= num*0.2 then 'top20%'when r <= num*0.4 and r > num*0.2 then '20%-40%'when r <= num*0.6 and r > num*0.4 then '40%-60%'when r <= num*0.8 and r > num*0.6 then '60%-80%'when r > num*0.8 then '80%以上'else NULLend as gmv_quantilefrom(select cate_id,total,row_number() over(order by total desc) r,count(1) over() numfrom(select cate_id,sum(gmv) totalfrom Twhere sale_date between '20190611' and '20190617'group by cate_id) t1) t2) t4 on t3.cate_id = t4.cate_id where t3.sale_date between '20190611' and '20190617' group by t3.cate_id七.case專題-連續區間問題
表:Logs
±--------------±--------+
| Column Name | Type |
±--------------±--------+
| log_id | int |
±--------------±--------+
id 是上表的主鍵。
上表的每一行包含日志表中的一個 ID。
后來一些 ID 從 Logs 表中刪除。
編寫一個 SQL 查詢得到 Logs 表中的連續區間的開始數字和結束數字。
將查詢表按照 start_id 排序。
查詢結果格式如下面的例子:
Logs 表:
±-----------+
| log_id |
±-----------+
| 1 |
| 2 |
| 3 |
| 7 |
| 8 |
| 10 |
±-----------+
結果表:
±-----------±-------------+
| start_id | end_id |
±-----------±-------------+
| 1 | 3 |
| 7 | 8 |
| 10 | 10 |
±-----------±-------------+
結果表應包含 Logs 表中的所有區間。
(1)使用兩個變量,一個@id用來記錄logid,可以比較當下log_id與之前log_id的差值,判斷是否連續。一個@num用來儲存連續狀態。
set @id=1,@num=0; select log_id,case when @id = log_id -1 then @num := @numelse @num := @num + 1end as n,@id := log_id from logs;(2)得到上述結果后,用num字段分組,最小log_id為start_id,最大log_id為end_id。
最終答案
八.case專題-學生成績分析
表:Enrollments
±--------------±--------+
| Column Name | Type |
±--------------±--------+
| student_id | int |
| course_id | int |
| grade | int |
±--------------±--------+
(student_id, course_id) 是該表的主鍵。
1.查詢每位學生獲得的最高成績和它所對應的科目,若科目成績并列,取 course_id 最小的一門。查詢結果需按 student_id 增序進行排序。
解法一:窗口函數
select * from(select student_id,course_id,grade,row_number() over(partition by student_id order by grade desc,course_id) rfrom Enrollments) a where r = 1 order by student_id;解法二: in解法(更簡單,快速)
select student_id,min(course_id) from Enrollments where (student_id,grade) in (select student_id,max(grade)from Enrollmentsgroup by student_id) group by student_id order by student_id;2.查詢每一科目成績最高和最低分數的學生,輸出courseid,studentid,score
解法一:Union
預備知識:union和union all
union對兩個結果集進行并集操作,兩個聯合的字段必須一樣
兩者區別是union要進行重復值掃描,不包括重復行,同時進行默認規則的排序,效率低
union all包括重復行,不進行排序
解法二:case-when
select c_id,max(case when r1=1 then s_id else null end) '最高分學生',max(case when r2=1 then s_id else null end) '最低分學生' from(select *,row_number() over(partition by c_id order by s_score desc) r1,row_number() over(partition by c_id order by s_score) r2from score) a group by c_id;九.case專題-學生做題情況分析
表t:做題日期(time),學生id(stu_id),題目id(exer_id)
1.統計10.1-10.10每天做新題的人的數量,重點在每天
select md,count(distinct t.stu_id) from t join(select stu_id,exer_id,min(covert(time,date)) mdfrom twhere covert(time,date) between '20191001' and '20191010'group by stu_id,exer_id) a on t.stu_id = a.stu_id and t.exer_id = a.exer_id group by md參考: 數分面試-SQL篇.
總結
以上是生活随笔為你收集整理的拼多多和猿辅导SQL题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式系列:搞懂组合模式,单对象与组合
- 下一篇: oracle11g数据库版本号,Orac