数仓面试中3个常考的SQL数据分析题

在数据类岗位招聘过程中,经常会考察求职者的SQL能力,这里整理了3个常考的SQL数据分析题,按照由简单到复杂排序,一起来测试一下你掌握了么?

文章首发于公众号【五分钟学大数据】,在公众号后台发送:大数据面试,送你一份最牛X的大数据面试题

PS:以下SQL代码在MySQL8.0及其以上版本运行。

题目1**:****找出每个部门工资第二高的员工**现有一张公司员工信息表employee,表中包含如下4个字段。

  • employee_id(员工ID):VARCHAR。

  • employee_name(员工姓名):VARCHAR。

  • employee_salary(员工薪资):INT。

  • department(员工所属部门ID):VARCHAR。

employee表的数据如下表所示。还有一张部门信息表department,表中包含如下两个字段。

  • department_id(部门ID):VARCHAR。

  • department_name(部门名称):VARCHAR。

department表的数据如下表所示。数据导入的代码如下:

sql 复制代码
DROP TABLE IF EXISTS employee;
CREATE TABLE employee(
employee_id VARCHAR(8),
employee_name VARCHAR(8),
employee_salary INT(8),
department VARCHAR(8)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
INSERT INTO
employee (employee_id,employee_name,employee_salary,department) 
VALUE ('a001','Bob',7000,'b1')
     ,('a002','Jack',9000,'b1')
     ,('a003','Alice',8000,'b2')
     ,('a004','Ben',5000,'b2')
     ,('a005','Candy',4000,'b2')
     ,('a006','Allen',5000,'b2')
     ,('a007','Linda',10000,'b3');

DROP TABLE IF EXISTS department;
CREATE TABLE department(
department_id VARCHAR(8),
department_name VARCHAR(8)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
INSERT INTO
department (department_id,department_name) 
VALUE ('b1','Sales')
     ,('b2','IT')
     ,('b3','Product');

问题:查询每个部门薪资第二高的员工信息。输出内容包括:

  • employee_id(员工ID)

  • employee_name(员工姓名)

  • employee_salary(员工薪资)

  • department_id(员工所属部门名称)

结果样例如下图所示。**可供参考的解题思路:**使用窗口函数根据部门ID分组,在组内按照员工薪资降序排列并记为ranking,然后将该处理后的表和部门信息表进行内连接,从而把部门名称关联进来,最后在连接后的表上使用ranking=2作为薪资第二高的条件进行WHERE筛选,选择需要的列,即可得到结果。**涉及知识点:**窗口函数、子查询、多表连接。本题的SQL代码如下,供读者参考:

sql 复制代码
SELECT  a.employee_id
       ,a.employee_name
       ,a.employee_salary
       ,b.department_id
FROM 
(
    SELECT  *
           ,RANK() OVER (PARTITION BY department ORDER BY employee_salary DESC) AS ranking
    FROM employee 
) AS a
INNER JOIN department AS b
ON a.department = b.department_id
WHERE a.ranking = 2;

题目2:****网站登录时间间隔统计现有一张网站登录情况表login_info,该表记录了所有用户的网站登录信息,包含如下两个字段。

  • user_id(用户ID):VARCHAR。

  • login_time(用户登录日期):DATE。

login_info表的数据如下表所示。数据导入的代码如下:

sql 复制代码
DROP TABLE IF EXISTS login_info;
CREATE TABLE login_info(
user_id VARCHAR(8),
login_time DATE
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
INSERT INTO
login_info (user_id,login_time) 
VALUE ('a001','2021-01-01')
,('b001','2021-01-01')
,('a001','2021-01-03')
,('a001','2021-01-06')
,('a001','2021-01-07')
,('b001','2021-01-07')
,('a001','2021-01-08')
,('a001','2021-01-09')
,('b001','2021-01-09')
,('b001','2021-01-10')
,('b001','2021-01-15')
,('a001','2021-01-16')
,('a001','2021-01-18')
,('a001','2021-01-19')
,('b001','2021-01-20')
,('a001','2021-01-23');

问题:计算每个用户登录日期间隔小于5天的次数。输出内容包括:

  • user_id(用户ID)

  • num(用户登录日期间隔小于5天的次数)

结果样例如下图所示。**可供参考的解题思路:**本题考查LEAD()函数在处理时间间隔问题上的使用方法,观察内层的查询部分,使用LEAD()函数在原有的login_time字段的基础上创造一列新的时间字段(即该用户下一次登录日期),内层查询代码如下:SELECT user_id

,login_time

,LEAD(login_time,1) OVER (PARTITION BY user_id ORDER BY login_time) AS next_login_time

FROM login_info;

查询结果如下图所示。
在上图中可以发现,经过LEAD()函数处理后,数据会根据user_id字段分组后按照login_time字段排序。经过内层的处理后,只需在外层筛选出next_login_time与login_time字段的日期差小于5天的数据,即最终统计的目标数据,这里使用了TIMESTAMPDIFF(DAY, login_time, next_login_time)计算日期差,最后分组聚合统计不同user_id的记录个数,即每个用户登录日期间隔小于5天的次数。**涉及知识点:**窗口函数、子查询、分组聚合、时间函数。本题的SQL代码如下,供读者参考:

sql 复制代码
SELECT  a.user_id
       ,COUNT(*) AS num
FROM 
(
    SELECT  user_id
           ,login_time
           ,LEAD(login_time,1) OVER (PARTITION BY user_id ORDER BY login_time) AS next_login_time
    FROM login_info
) AS a
WHERE TIMESTAMPDIFF(DAY, login_time, next_login_time) < 5 
GROUP BY user_id;

题目3:****用户购买渠道分析现有一张用户购买信息表purchase_channel,该表记录了用户在某购物平台的购物信息,该购物平台具有网页端(web)和手机端(app)两种访问方式,表中包含如下4个字段。

  • **user_id(用户ID):**VARCHAR。

  • **channel(用户购买渠道):**VARCHAR。

  • **purchase_date(购买日期):**DATE。

  • **purchase_amount(购买金额):**INT。

purchase_channel表的数据如下表所示。数据导入代码如下:

sql 复制代码
DROP TABLE IF EXISTS purchase_channel;
CREATE TABLE purchase_channel(
user_id VARCHAR(8),
channel VARCHAR(8),
purchase_date DATE,
purchase_amount INT(8)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
INSERT INTO
purchase_channel (user_id,channel,purchase_date,purchase_amount) 
VALUE ('a001','app','2021-03-14',200)
     ,('a001','web','2021-03-14',100)
     ,('a002','app','2021-03-14',400)
     ,('a001','web','2021-03-15',3000)
     ,('a002','app','2021-03-15',900)
     ,('a003','app','2021-03-15',1000);

问题:查询每天仅使用手机端的用户、仅使用网页端的用户和同时使用网页端和手机端(both)的不同用户人数和总购物金额,并且即使某天某渠道没有用户的购买信息,也需要展示。**输出内容包括:**purchase_date(日期)channel(购买渠道)sum_amount(总购买金额)total_users(不同用户人数)结果样例如下图所示。**可供参考的解题思路:**根据用户ID和日期进行分组,通过统计用户在各购买渠道购物的记录个数来判断某用户在某日期购物时采用的访问方式(web、app和both)。其中,web和app可以通过一个SELECT语句查询,both则可以通过另一个SELECT语句查询。将两部分使用UNION连接在一起,并将以上部分作为子查询内部,在子查询外部统计不同购买日期、购买渠道的总购买金额和总购买用户。本部分SQL代码如下:

sql 复制代码
SELECT  purchase_date 
       ,channel 
       ,SUM(sum_amount) sum_amount 
       ,SUM(total_users) total_users
FROM 
(
    SELECT  purchase_date 
           ,MIN(channel) channel 
           ,SUM(purchase_amount) sum_amount 
           ,COUNT(DISTINCT user_id) total_users
    FROM purchase_channel
    GROUP BY  purchase_date
             ,user_id
    HAVING COUNT(DISTINCT channel) = 1 UNION
    SELECT  purchase_date 
           ,'both' channel 
           ,SUM(purchase_amount) sum_amount 
           ,COUNT(DISTINCT user_id) total_users
    FROM purchase_channel
    GROUP BY  purchase_date
             ,user_id
    HAVING COUNT(DISTINCT channel) > 1 
) c
GROUP BY  purchase_date
         ,channel;

本部分输出结果如下图所示。上述部分似乎已经完成了本题要求,但仔细观察就会发现,题目要求即使某天某渠道没有用户的购买信息,也需要展示。而想要展示更全的信息,则考虑使用最全的信息(所有日期和3个渠道的笛卡尔积)与刚查询出的结果数据表进行LEFT JOIN连接,即可得到两张表根据日期和渠道进行连接的结果。**涉及知识点:**UNION、分组聚合、数据去重。本题的SQL代码如下,供读者参考:

sql 复制代码
SELECT  t1.purchase_date
       ,t1.channel
       ,t2.sum_amount
       ,t2.total_users
FROM 
(
    SELECT  DISTINCT a.purchase_date 
           ,b.channel
    FROM purchase_channel a, 
    (
        SELECT  "app" AS channel 
        UNION
        SELECT  "web" AS channel 
        UNION
        SELECT  "both" AS channel 
    ) b
) t1
LEFT JOIN 
(
SELECT 
purchase_date,
channel,
SUM(sum_amount) sum_amount,
SUM(total_users) total_users
FROM (
SELECT  purchase_date 
           ,MIN(channel) channel 
           ,SUM(purchase_amount) sum_amount 
           ,COUNT(DISTINCT user_id) total_users
    FROM purchase_channel
    GROUP BY  purchase_date,user_id
    HAVING COUNT(DISTINCT channel) = 1 
    UNION
    SELECT  purchase_date 
           ,'both' channel 
           ,SUM(purchase_amount) sum_amount 
           ,COUNT(DISTINCT user_id) total_users
    FROM purchase_channel
    GROUP BY  purchase_date,user_id
    HAVING COUNT(DISTINCT channel) > 1
)c GROUP BY purchase_date, channel
) t2
ON t1.purchase_date = t2.purchase_date AND t1.channel = t2.channel;

这些题目你做出了么?

文章首发于公众号【五分钟学大数据】,在公众号后台发送:大数据面试,送你一份最牛X的大数据面试题

相关推荐
奥顺1 小时前
PHP与AJAX:实现动态网页的完美结合
大数据·mysql·开源·php
中东大鹅3 小时前
分布式数据存储基础与HDFS操作实践
大数据·linux·hadoop·分布式·hbase
Y编程小白4 小时前
Git版本控制工具--基础命令和分支管理
大数据·git·elasticsearch
不爱学习的YY酱5 小时前
【操作系统不挂科】<内存管理-文件系统实现(18)>选择题(带答案与解析)
java·大数据·数据库
guanpinkeji5 小时前
陪诊小程序搭建,打造一站式陪诊服务
大数据·小程序·小程序开发·陪诊·陪诊小程序
胡耀超6 小时前
如何从全局视角规划项目与战略决策(“精准接送”案例、技术架构设计与选型、业务逻辑及产品商业模式探讨)
大数据·数据挖掘·软件架构·商业模式·数据管理
标贝科技6 小时前
标贝科技受邀出席2024ADD数据应用场景大会 共议数据要素发展新契机
大数据·数据库·人工智能·科技·语言模型·数据挖掘
出发行进7 小时前
Hive其五,使用技巧,数据查询,日志以及复杂类型的使用
大数据·hive·数据分析
ssxueyi7 小时前
数据仓库有哪些?
大数据·数据仓库·数据湖
武子康7 小时前
大数据-256 离线数仓 - Atlas 数据仓库元数据管理 正式安装 启动服务访问 Hive血缘关系导入
大数据·数据仓库·hive·hadoop