如何准备一场成功的SQL面试?

2020 年 8 月 20 日

如何准备一场成功的SQL面试?

本文最初发布于 towards data science 网站, 经原作者授权由 InfoQ 中文站翻译并分享。


SQL 是用于数据分析和数据处理的最重要的编程语言之一,因此与数据科学相关的工作(例如数据分析师、数据科学家和数据工程师)在面试时总会问到关于 SQL 的问题。SQL 面试问题旨在评估应聘者的技术和解决问题的能力。因此对于应聘者来说,关键在于不仅要根据样本数据编写出正确的查询,而且还要像对待现实数据集一样考虑各种场景和边缘情况。


我以前也设计过针对数据科学候选人的 SQL 面试问题,自己也在大型技术公司和初创公司中主持过许多次 SQL 面试。在这篇文章中,我将介绍 SQL 面试问题中常见的模式,并提供一些在 SQL 查询中巧妙处理它们的技巧。


问问题


要搞定一场 SQL 面试,最重要的是尽量多问问题,获取关于给定任务和数据样本的所有细节。充分理解需求后,接下来你就可以节省很多迭代问题的时间,并且能很好地处理边缘情况。


我注意到许多候选人经常还没完全理解 SQL 问题或数据集,就直接开始编写解决方案了。之后,等我指出他们解决方案中存在的问题后,他们只好反复修改查询。最后,他们在迭代中浪费了很多面试时间,甚至可能到最后都没有找到正确的解决方案。


我建议大家在参加 SQL 面试时,就当成是自己在和业务伙伴共事。所以在你提供解决方案之前,应该要针对数据请求了解清楚所有的需求。


示例


查找薪水最高的前3名员工。



样本 employee_salary 表。


这里你应该要求面试官说清楚“前三名”具体是什么意思。我应该在结果中包括 3 名员工吗?你要我怎样处理关系?此外,请仔细检查样本员工数据。salary 字段的数据类型是什么?在计算之前是否需要清除数据?


选哪一个 JOIN



在 SQL 中,JOIN 通常用来合并来自多个表的信息。有四种不同类型的 JOIN,但在大多数情况下,我们只使用 INNER、LEFT 和 FULLJOIN,因为 RIGHTJOIN 并不是很直观,还可以使用 LEFTJOIN 很简单地重写。在 SQL 面试中,需要根据给定问题的特定要求选择你要使用的正确 JOIN。


示例


查找每个学生参加的课程总数。(提供学生id、姓名和选课的数量。)



样本 student 和 class_history 表。


你可能已经注意到了,并非所有出现在 class_history 表中的学生都出现在了 student 表中,这可能是因为这些学生已经毕业了。(这在事务数据库中实际上是非常典型的情况,因为不再活跃的记录往往会被删除。)根据面试官是否希望结果中包含毕业生,我们需要使用 LEFT JOIN 或 INNER JOIN 来组合两个表:


WITH class_count AS (     SELECT student_id, COUNT(*) AS num_of_class     FROM class_history     GROUP BY student_id ) SELECT     c.student_id,     s.student_name,     c.num_of_class FROM class_count c -- CASE 1: include only active students JOIN student s ON c.student_id = s.student_id -- CASE 2: include all students -- LEFT JOIN student s ON c.student_id = s.student_id 
复制代码



GROUP BY


GROUP BY 是 SQL 中最重要的功能,因为它广泛用于数据聚合。如果在一个 SQL 问题中看到诸如求和、平均值、最小值或最大值之类的关键字,这就表明你可能应该在查询中使用 GROUP BY 了。一个常见的陷阱是在 GROUP BY 过滤数据时混淆 WHERE 和 HAVING——我见过很多人犯了这个错误。


示例


计算每个学生在每个学年的必修课程平均GPA,并找到每个学期中符合Dean’s List(GPA≥3.5)资格的学生。



样本 gpa_history 表。


由于我们在 GPA 计算中仅考虑必修课程,因此需要使用 WHERE is_required = TRUE 来排除选修课程。我们需要每位学生在每学年的平均 GPA,因此我们将同时 GROUP BY student_id 和 school_year 列,并取 gpa 列的平均值。最后,我们只保留学生平均 GPA 高于 3.5 的行,可以使用 HAVING 来实现。合起来是下面这样:


SELECT     student_id,     school_year,     AVG(gpa) AS avg_gpa FROM gpa_history WHERE is_required = TRUE GROUP BY student_id, school_year HAVING AVG(gpa) >= 3.5 
复制代码


请记住,每当在查询中使用 GROUP BY 时,都只能选择 group-by 列和聚合列,因为其他列中的行级信息已被舍弃。


有些人可能想知道 WHERE 和 HAVING 之间有什么区别,或者为什么我们不是简单地编写 HAVING avg_gpa >= 3.5,却要使用比较麻烦的函数。我将在下一节中详细解释。


SQL 查询执行顺序


大多数人会从 SELECT 开始,从上到下编写 SQL 查询。但你知道 SQL 引擎执行函数时要到后面才执行 SELECT 吗?以下是 SQL 查询的执行顺序:


  1. FROM, JOIN

  2. WHERE

  3. GROUP BY

  4. HAVING

  5. SELECT

  6. DISTINCT

  7. ORDER BY

  8. LIMIT, OFFSET


再次考虑前面的示例。因为我们想在计算平均 GPA 之前过滤掉选修课程,所以我使用 WHERE is_required = TRUE 代替 HAVING,因为 WHERE 会在 GROUP BY 和 HAVING 之前执行。我不能编写 HAVING avg_gpa >= 3.5 的原因是,avg_gpa 被定义为 SELECT 的一部分,因此无法在 SELECT 之前执行的步骤中引用它。


我建议在编写查询时遵循引擎的执行顺序,这在编写复杂查询时会很有用。



Window 函数


Window 函数也经常出现在 SQL 面试中。共有五种常见的 Window 函数:


  • RANK / DENSE_RANK / ROW_NUMBER :它们通过排序特定列来为每行分配一个排名。如果给出了任何分区列,则行将在其所属的分区组中排名。

  • LAG / LEAD :它根据指定的顺序和分区组从前一行或后一行检索列值。


在 SQL 面试中,重要的是要了解排名函数之间的差异,并知道何时使用 LAG/LEAD。


示例


查找每个部门中薪水最高的前3名员工。



另一个示例 employee_salary 表。


当一个 SQL 问题要求计算“TOP N”时,我们可以使用 ORDER BY 或排名函数来回答问题。但在这个示例中,它要求计算“每个 Y 中的 TOP N X”,这强烈暗示我们应该使用排名函数,因为我们需要对每个分区组中的行进行排名。


以下查询恰好能找到 3 名薪水最高的员工,而不论他们的关系如何:


WITH T AS ( SELECT     *,     ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY employee_salary DESC) AS rank_in_dep FROM employee_salary) SELECT * FROM T WHERE rank_in_dep <= 3 -- Note: When using ROW_NUMBER, each row will have a unique rank number and ranks for tied records are assigned randomly. For exmaple, Rimsha and Tiah may be rank 2 or 3 in different query runs. 
复制代码


此外,根据关系的处理方式,我们可以选择其他排名函数。同样,细节是很重要的!



ROW_NUMBER,RANK 和 DENSE_RANK 函数的结果比较。



重复项


SQL 面试中的另一个常见陷阱是忽略数据重复。尽管样本数据中的某些列似乎具有不同的值,但面试官还是希望候选人考虑所有可能性,就像他们在处理真实数据集一样。例如,在上一个示例 employee_salary 表中,可以让雇员共享相同的名称。


要避免由重复项导致的潜在问题,一种简单方法是始终使用 ID 列唯一地标识不同的记录。


示例


使用employee_salary表查找每个部门所有员工的总薪水。


正确的解决方案是 GROUP BY employee_id,然后使用 SUM(employee_salary)计算总薪水。如果需要雇员姓名,请在末尾与 employee 表联接以检索雇员姓名信息。


错误的方法是使用 GROUP BY employee_name。


NULL


在 SQL 中,任何谓词都可以产生三个值之一:true,false 和 NULL,后者是 unknown 或 missing 数据值的保留关键字。处理 NULL 数据集时可能会意外地很棘手。在 SQL 面试中,面试官可能会特别注意解决方案是否处理了 NULL 值。有时,很明显有一列是不能 nullable 的(例如 ID 列),但对于其他大多数列来说,很有可能会有 NULL 值。


我建议确认示例数据中的关键列是否为 nullable,如果可以,请利用 IS(NOT)NULL,IFNULL 和 COALESCE 之类的函数来覆盖这些边缘情况。


(想要了解关于如何处理 NULL 值的更多信息?请查阅我写的在 SQL 中使用 NULL 的指南。「 https://towardsdatascience.com/demystify-null-values-in-sql-bc7e7e1b913a」)


交流


最后一点也非常重要:在 SQL 面试期间要随时与面试官沟通交流。


我面试过的许多候选人都很沉默寡言,有疑问的时候才会知声。当然如果他们最终给出了完美的解决方案,那也不是什么问题。但是,在技术面试期间保持沟通交流往往会是有价值的。例如,你可以谈论对问题和数据的理解,说明你计划如何解决问题,为什么使用某些函数而不是其他选项,以及正在考虑哪些极端情况。


总结


  • 首先要提问,收集所需的细节。

  • 在INNER,LEFT和FULL JOIN之间谨慎选择。

  • 使用GROUP BY聚合数据并正确使用WHERE和HAVING。

  • 了解三个排名函数之间的差异。

  • 知道何时使用LAG/LEAD窗口函数。

  • 如果在创建复杂的查询时遇到困难,请尝试遵循SQL执行顺序。

  • 考虑潜在的数据问题,例如重复和NULL值。

  • 与面试官交流你的思路。


为了帮助大家了解如何在实际的 SQL 面试中使用这些策略,我在下面的视频中从头到尾一步步介绍了一个 SQL 面试问题例子:


https://youtu.be/EjETvPfiwYw


希望这篇指南可以帮助你准备好下一次数据科学面试。祝好运!


想了解更多数据工程知识?查看我关于数据科学的数据工程 101 专栏( https://towardsdatascience.com/tagged/data-engineering-101)。


原文链接: https://towardsdatascience.com/crack-sql-interviews-6a5fc90ec763


2020 年 8 月 20 日 15:041131

评论 1 条评论

发布
用户头像
right join图画错了吧
2020 年 08 月 22 日 09:27
回复
没有更多评论了
发现更多内容

我在项目中是这样配置Vue的

前端有的玩

Java Vue 前端 框架设计

女员工被阿里录取工资二万六,辞职时被领导挽留:给你4万留下

程序员生活志

阿里 女程序员

抢滩新基建,百度还会输给阿里和腾讯吗?

ToB行业头条

三大 OSS 缓存加速系统巅峰对决

苏锐

hadoop cache JuiceFS JindoFS Performance

智慧4S店解决方案发布,看英特尔如何引领汽车销售行业变革

飞天鱼2017

Mysql插入百万条数据

Java小咖秀

MySQL 运维 数据

看动画学算法之:排序-插入排序

程序那些事

Java 数据结构 算法 插入排序

《重学 Java 设计模式》PDF 出炉了 - 小傅哥,肝了50天写出18万字271页的实战编程资料

小傅哥

Java 设计模式 小傅哥 重构 代码质量

设计模式六大原则

刘志刚

设计原则

阿里拍卖,能不能拍到点儿上?

ToB行业头条

如何把百万级别的订单根据金额排序

码哥字节

数据结构 排序算法

在前端如何玩转 Word 文档

阿宝哥

html markdown word

设计模式(1)—什么是设计模式?设计模式的六大原则是什么?

爱嘤嘤嘤斯坦

Java 程序员 编程语言 设计模式 23种设计模式

Spring5-Reactor函数式编程

小技术君

spring reactor Spring5 springboot

人人都需要一份自己的「使用说明书」

非著名程序员

程序员 程序人生 提升认知 独立思考 自我思考

推荐系统大规模特征工程与FEDB的Spark基于LLVM优化

范式AI云

spark Sparksql 推荐系统 LLVM FEDB

吴恩达推荐笔记:22张图总结深度学习全部知识

程序员生活志

学习 吴恩达

讲烂了的mysql,今天再给大家重温一下

爱嘤嘤嘤斯坦

Java MySQL 数据库 编程 mysql事务

自动化测试首先是一种工作文化

wangwei1237

自动化测试 测试文化

计算机网络基础(一)---计算机网络概览篇

书旅

php laravel 计算机网络

MobTech袤博与百度战略签约 携手布局数据智能产业新蓝图

Geek_116789

腾讯的ToB梦想

ToB行业头条

为什么我们需要制品管理?

Man

DevOps nexus 制品库管理 Artifactory

抽象工厂模式

Leetao

Python 面试 设计模式

2020,是中国SaaS行业的机遇之年?

ToB行业头条

时间去哪了?

escray

CAP原理简述

刘志刚

第6周-作业1

seng man

第6周-作业2-总结

seng man

IDC2020 Q1通用服务器数据发布,浪潮信息成绩喜人

Geek_116789

laravel redis队列不执行

kaer

laravel redis Queue

如何准备一场成功的SQL面试?-InfoQ