赞
踩
大家好,我是宁一。
SQL不仅仅是每个技术开发必须掌握的技能,
也是数据分析、商业分析招聘中,必考的能力。
这次给大家整理了SQL大厂春招的真题,每道题都加了独家详细解析。
整理完后,我的脑袋是蒙蒙的。
大厂就是大厂,这个烧脑程度,拜服!
之前也出过一篇大厂实战真题,大家可以一起食用。
刷完这些题,相信大家能找到大厂出题的规律,大厂比较重视综合能力,题目不会只考一个知识点。
比如大多题目都综合考察了聚合函数、窗口函数、嵌套查询、索引、日期函数等知识点。
所以我们各个知识点都要熟练掌握。
这周六(3月26日)我会出SQL入门进阶课程。
不是广告,自己写的,免费的~
打算用最直白的语言给大家讲清楚SQL。从小白的角度入手,手把手教你学习SQL的入门以及进阶知识。
有些同学可能看过我之前的小程序实战课程,知道我的讲课风格就是:不说废话,只讲干货。
从最基础的增删改查,到进阶的视图、触发器、事件、事务等都会涉及。实战举例+作业巩固,争取用一门课让大家掌握SQL,可以顺利面试、参与工作。
感兴趣的同学可以关注蹲一下哦~
下面是大厂春招真题:
嵌套查询,顾名思义,就是查询语句的嵌套,即在外部查询中还包含一个内部查询。
内部查询也叫子查询,查询结果可以作为一个临时表来使用,完成更为复杂表联结数据的检索功能。
嵌套查询是由内而外进行分析,子查询的结果作为主查询的查询条件。子查询中一般不使用order by子句,只能对最终查询结果进行排序。
经典问题:
下面表格是用户访问表users,记录了用户id(usr_id)和访问日期(log_date),查询出每个用户最近一次的登录记录和每个用户登录总次数(同一天多次登录认为是一次)。
实例结果:
解题思路:
根据示例结果,第二列current_day,是每个用户访问日期的最大值,直接用MAX聚合函数就可以。
第三列sum_day是每个用户登录总次数,因为同一天多次登录认为是一次,所以通过将原表log_date列格式化去掉时间,得出用户登录的日期,比如2021-05-03 01:00:08 格式化成 2021-05-03。我们就可以将日期去重,得到每个用户的登录总次数。
SELECT
usr_id,
log_date,
DATE_FORMAT(log_date,'%Y-%m-%d') AS days
FROM Users
SELECT usr_id,
MAX(log_date) AS current_day,
COUNT(DISTINCT days) AS sum_day
FROM(
SELECT
usr_id,
log_date,
DATE_FORMAT(log_date,'%Y-%m-%d') AS days
FROM Users
) AS a
GROUP BY usr_id;
这道题涵盖的知识点很多,包括索引、日期函数、聚合函数、窗口函数、嵌套查询。
能做出来,说明SQL掌握的已经很棒了,可以放心去面试。
经典问题:
我们现在有一个数据表DateTable,如下:
问题一:对数据表DateTable的dates列添加索引。
问题二:通过SQL语句,输入下方结果。
这个就是考察索引语法的,很简单。
给DateTable表的dates列添加一个名为index_date的索引
CREATE INDEX index_date ON DateTable(dates);
查看索引
SHOW INDEX FROM DateTable;
解题思路:
我们查看输出结果,第一列是年,第二列是月,这两列直接用日期函数就可以得到。
第四列,是将cost列按年汇总,第五列是将cost列全部汇总,因为每一行都有汇总记录,所以我们不应该单纯用聚合函数SUM来计算,而是用窗口函数+聚合函数SUM。
SELECT dates,
YEAR(dates) AS years,
MONTH(dates) AS months,
SUM(cost) AS cost
FROM DateTable
GROUP BY dates
SELECT years,months,cost,
SUM(cost) OVER(PARTITION BY years ORDER BY months) ysum,
SUM(cost) OVER(ORDER BY dates) sum
FROM(
SELECT dates,
YEAR(dates) AS years,
MONTH(dates) AS months,
SUM(cost) AS cost
FROM DateTable
GROUP BY dates
) AS a
可以使用下方语句快速建表测试:
create table DateTable (
dates datetime,
cost int
);
insert into DateTable values
("2020/07/12",10),
("2020/11/30",3),
("2019/2/9",20),
("2019/3/31",23),
("2022/2/8",99),
("2021/7/31",10);
经典问题:
查询支付日期在2022.3.20之后的购买商品超过一次的用户,按照最新购买时间倒叙排列。
解题思路:
先找出2022.3.20之后的数据记录,再将这些记录根据user_id进行分组,通过COUNT聚合函数查出每组条数大于1的记录,最后还要按照最新购买时间倒叙排列。
SELECT user_id
FROM Products
WHERE purchase_date>"2022-03-20"
GROUP BY user_id
HAVING COUNT(*)>1销售
ORDER BY max(purchase_date) desc
这道题看着很简单,但是里面埋了几个陷阱需要注意:
having作用和where差不多,用来在分组之后,筛选分组才产生的数据。having后面可以直接跟聚合函数,如果要跟字段的话,这个字段必须在select后面提到过,where则不用
MySQL中,在使用聚合函数的时候,select后面的字段,必须出现在group by的后面,比如这道题中的user_id字段。
MySQL中,在使用聚合函数的时候,order_by后面的语句要注意使用聚合函数的字段,或者group by后面的字段。
上面的字段使用不太了解,没关系,我们来讲讲当一个查询语句同时出现where,group by,having,order by的时候,执行顺序和编写顺序,你就明白了。
FROM --> WHERE --> GROUP BY --> SELECT --> HAVING --> ORDER BY
我们再结合上面的题目看一下执行顺序:
1.执行where 语句对全表数据做筛选,FROM Products WHERE purchase_date>"2022-03-20”,返回第1个结果集。
2.针对第1个结果集使用group by分组,GROUP BY user_id,返回第2个结果集。
3.针对第2个结果集中的每1组数据执行SELECT user_id,有几组就执行几次,返回第3个结果集。
4.针对第3个结集执行HAVING COUNT(*)>1进行筛选,返回第4个结果集。
5.最后针对第4个结果集排序,ORDER BY max(purchase_date) desc
经典问题:
现在有一个订单表orders,包括订单id(Oid)、商品id(product_id)、销售渠道(channel)、订单量(amount)。我们根据这个表,选取订单量前4的商品,并且选出每个商品订单量排名前2的销售渠道。
示例结果:
解题思路:
根据题目以及示例结果,我们最终要得到订单量最高的4个产品,以及每个产品对应排名前2的销售渠道。
我们可以先得到订单量排名前4的结果集1,再得到每个商品对应销售渠道的订单量排名结果集2,通过join将结果集1和结果集2连接得到最终结果。
SELECT product_id,
SUM(amount) AS amt
FROM Orders
GROUP BY product_id
ORDER BY amt desc
LIMIT 4
SELECT product_id,
channel,
ROW_NUMBER() OVER(PARTITION BY product_id ORDER BY amount DESC) AS rk
FROM Orders
SELECT b.product_id,b.channel FROM( SELECT product_id, SUM(amount) AS amt FROM Orders GROUP BY product_id ORDER BY amt desc LIMIT 4 ) AS a JOIN ( SELECT product_id, channel, ROW_NUMBER() OVER(PARTITION BY product_id ORDER BY amount DESC) AS rk FROM Orders ) AS b ON a.product_id = b.product_id WHERE b.rk <=2
现在有一个Products表,推荐出每个user_id,和他相似的用户所购买过的product。
要求:该用户已经购买过的不再推荐。
相似用户的定义:曾经购买过2种或2种以上的相同商品。
示例结果:
解题思路:
这道题我们先找出相似的用户,比如用户A和用户B是相似用户,我们需要将B购买过,而A没有购买过的产品推荐给A。这个跟实际业务很相似了,还需要费点脑筋的,我们来一步步拆解。
SELECT a.user_id as uid_a,b.user_id as uid_b,
COUNT(DISTINCT b.product_id) as same_pro
FROM Products AS a
JOIN Products AS b
ON a.user_id != b.user_id
AND a.product_id = b.product_id
GROUP BY uid_a,uid_b
HAVING same_pro>=2
SELECT x.uid_a,x.uid_b,y.product_id
FROM(
SELECT a.user_id AS uid_a,b.user_id AS uid_b,
COUNT(DISTINCT b.product_id) AS same_pro
FROM Products AS a
JOIN Products AS b
ON a.user_id != b.user_id
AND a.product_id = b.product_id
GROUP BY uid_a,uid_b
HAVING same_pro>=2
) AS x
JOIN Products AS y
ON x.uid_a = y.user_id
我们用的是左连接,即使不满足y.product_id = z.product_id,第二步获得的结果集也会全部显示,不满足条件的会显示null。这一步结果已经出来了,就是第四列为null 的记录。
SELECT x.uid_a,x.uid_b,y.product_id,z.product_id FROM( SELECT a.user_id AS uid_a,b.user_id AS uid_b, COUNT(DISTINCT b.product_id) AS same_pro FROM Products AS a JOIN Products AS b ON a.user_id != b.user_id AND a.product_id = b.product_id GROUP BY uid_a,uid_b HAVING same_pro>=2 ) AS x JOIN Products AS y ON x.uid_a = y.user_id LEFT JOIN Products AS z ON x.uid_b = z.user_id AND y.product_id = z.product_id
最终结果如下:
SELECT x.uid_b AS user_id,y.product_id FROM( SELECT a.user_id AS uid_a,b.user_id AS uid_b, COUNT(DISTINCT b.product_id) AS same_pro FROM Products AS a JOIN Products AS b ON a.user_id != b.user_id AND a.product_id = b.product_id GROUP BY uid_a,uid_b HAVING same_pro>=2 ) AS x JOIN Products AS y ON x.uid_a = y.user_id LEFT JOIN Products AS z ON x.uid_b = z.user_id AND y.product_id = z.product_id WHERE z.product_id IS NULL;
现在有主播表a:包括主播id(upid)、直播间id(rid)、开播时间(stime)
观众表b:包括观众id(uid)、进入的直播间id(rid)、进入时间(intime)
找出开播三分钟内无人进入的直播房间号。
解题思路:
我们先通过左连接,得到主播对应的3分钟进入直播间的观众,如果没有对应的观众,就是我们要找的记录。
比如主播是12:10分开播,观众在12:12分进入,这符合开播3分钟内进入的要求。
用数据表示就是:观众时间减去3分钟,是12:09分,12:10分>12:09分,说明用户在开播3分钟内进入直播间。
SELECT a.upid,a.rid,b.uid
FROM a
LEFT JOIN b
ON a.rid = b.rid
AND a.stime > date_add(b.intime,INTERVAL -3 minute)
SELECT a.upid,a.rid
FROM a
LEFT JOIN b
ON a.rid = b.rid
AND a.stime > date_add(b.intime,INTERVAL -3 minute)
WHERE b.uid IS NULL;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。