ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

数据分析SQL面试全攻略:从基础语法到业务场景高频考点精讲

数据分析SQL面试全攻略:从基础语法到业务场景高频考点精讲 1. 面试到底考什么数据分析SQL面试的底层逻辑做数据分析或者商业分析岗位面试SQL基本是绕不开的一道硬门槛。我面过不少候选人也帮朋友做过模拟面试一个很直观的感受是很多人不是不会写SQL而是不知道面试官到底在考察什么导致准备方向偏了。SQL题目看着是考语法实际上考的是三样东西逻辑拆解能力、业务理解深度、代码习惯。先说逻辑拆解。数据分析场景里的SQL题从来不会直接告诉你“用LEFT JOIN连接两张表”而是给你一个业务问题比如“统计每个品类下销量排名前3的商品”。这时候你需要自己把问题拆解成先算每个商品在品类内的销量再按品类分组做排名最后过滤出前3名。这个拆解过程就是面试官最想看到的。再说业务理解。同样是“求留存率”不同公司的口径可能完全不同。是按注册日期算还是按首次活跃日期算留存是次日留存还是7日留存活跃的定义是“有过任意行为”还是“有过核心行为”这些问题在题目描述里往往不会写全面试官就是想看你会不会主动追问澄清。能在写SQL之前把业务口径问清楚的人在我这里一定加分。最后是代码习惯。一个完整的SQL面试题通常要求你现场写代码面试官一边看一边问。这时候代码的可读性、健壮性就很重要了。是习惯用SELECT *还是显式列出字段空值处理有没有考虑到排序的升降序有没有弄反这些细节比“能不能写出正确答案”更能反映一个人平时的工作习惯。基于我接触到的实际面试题SQL考察的深度大致可以分成三个层次基础语法层JOIN、聚合、筛选、去重、逻辑进阶层窗口函数、子查询、CTE、业务应用层留存、复购、TopN、连续登录等经典场景。下面我按这个分层把高频考点一个个拆开讲每一道题都会结合真实业务场景来说明而不是干巴巴地背语法。2. 基础语法题别在JOIN和去重上翻车别小看基础题很多工作了三五年的人照样在JOIN和去重的细节上栽跟头。这一部分我建议你当成“送分题”来对待但前提是每个细节你都真正吃透了。2.1 五种JOIN的本质与最容易踩的坑表连接是SQL面试必考几乎每轮面试都会出现。核心就五种INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL OUTER JOIN、CROSS JOIN。面试最常见的考点是LEFT JOIN和INNER JOIN的区别以及ON和WHERE放在LEFT JOIN里为什么会结果不同。我直接说一个经典陷阱。面试官给你两张表一张用户表user_id, user_name一张订单表order_id, user_id, amount让你统计每个用户的订单总金额没有订单的用户也要列出来。大部分人能写出SELECT u.user_id, u.user_name, SUM(o.amount) AS total_amount FROM user u LEFT JOIN orders o ON u.user_id o.user_id GROUP BY u.user_id, u.user_name;这个答案本身没问题。但如果面试官追加一句“请注意过滤掉无效订单status ‘invalid’”很多人会顺手在WHERE里写SELECT u.user_id, u.user_name, SUM(o.amount) AS total_amount FROM user u LEFT JOIN orders o ON u.user_id o.user_id WHERE o.status ! invalid GROUP BY u.user_id, u.user_name;结果就出问题了。LEFT JOIN之后没有订单的用户右表字段都是NULLNULL ! invalid这个条件在SQL里不成立这些用户整行被过滤掉了。你违背了“没有订单的用户也要列出来”这个前提。正确做法是把过滤条件放到ON子句里SELECT u.user_id, u.user_name, SUM(o.amount) AS total_amount FROM user u LEFT JOIN orders o ON u.user_id o.user_id AND o.status ! invalid GROUP BY u.user_id, u.user_name;这个细节我几乎在每次模拟面试都会讲因为它太典型了。ON子句负责“连接时决定哪些行匹配”WHERE负责“连接完成后决定哪些行保留”。LEFT JOIN的场景里右表过滤条件写错位置LEFT就变成了INNER。提示见到LEFT JOIN题目先问自己一个问题——如果右表没有匹配行这个用户还要不要出现在结果里要那右表的所有过滤条件都写在ON里面。2.2 聚合与去重GROUP BY、DISTINCT、COUNT的细节去重是另一个高频考点。大家可以看看热词里“sql语句去重查询”“清洗---sql语句去重”出现频率多高就知道工作中这是逃不掉的。面试一般考察两种去重简单去重和分组去重。简单去重用DISTINCT比如统计有多少个不同的用户下了单SELECT COUNT(DISTINCT user_id) FROM orders;有一点要注意COUNT(DISTINCT user_id)不会计入NULL值。如果user_id允许为空那么COUNT(DISTINCT user_id)和COUNT(DISTINCT user_id) COUNT(DISTINCT CASE WHEN user_id IS NULL THEN 1 END)结果可能不一样。实务中用户ID不会为NULL但面试时有人问起来你能答出这个细节会很加分。分组去重通常用ROW_NUMBER()这个后面细说。这里先提醒一个更隐蔽的坑COUNT(*)和COUNT(字段)的区别。COUNT()统计的是行数COUNT(字段)统计的是该字段非NULL值的数量。比如你要统计每个用户的订单数用COUNT(order_id)没问题但如果某张表的order_id允许为NULL那结果就会少于实际行数。习惯上用COUNT()或COUNT(1)更稳妥。再补充一个工作中能救命的小技巧。数据清洗场景里“去重”往往不是简单DISTINCT而是“同一用户保留最新一条记录”。这个需求用DISTINCT做不了需要结合窗口函数WITH ranked AS ( SELECT user_id, action_time, behavior, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY action_time DESC) AS rn FROM user_behavior ) SELECT user_id, action_time, behavior FROM ranked WHERE rn 1;这道题在我面试别人的时候经常出现因为它是“去重”场景下最贴近实战的一个问题而且天然衔接窗口函数考点。2.3 空值处理的正确姿势热词里有“sql去除空值”说明这也是很多人工作时的痛点。面试不太直接考“怎么去除空值”但会在题目里埋空值陷阱。两种常见考法一是用IS NULL做判断二是用COALESCE或IFNULL做默认值替换。先说IS NULL。SQL里判断空值不能写“ NULL”任何与NULL做等值比较的结果都是未知UNKNOWN在WHERE里会被过滤掉。这个基础错误通常问的是概念你答“NULL只能用IS NULL或者IS NOT NULL判断”就过关了。再说COALESCE。比如统计每个用户的订单总额没有订单的用户要给0而不是NULLSELECT u.user_id, COALESCE(SUM(o.amount), 0) AS total_amount FROM user u LEFT JOIN orders o ON u.user_id o.user_id GROUP BY u.user_id;COALESCE可以传多个参数返回第一个非NULL的值MySQL里也常用IFNULL(expr1, expr2)。相比之下COALESCE是标准SQL跨数据库通用性更好我面试时更推荐写COALESCE。还有一个细节要留意COUNT和SUM遇到NULL的处理方式不同。COUNT(字段)忽略NULLSUM(字段)也忽略NULL——如果该字段全为NULLSUM返回NULL而不是0。很多人死在这上面所以业务上“求总和”时最好用COALESCE(SUM(amount), 0)包一层既能防空值也能统一返回值语义。3. 窗口函数专题数据分析师的分水岭基础语法大家都会真正拉开差距的是窗口函数。我面试过的候选人里能熟练使用窗口函数的大概只有一半左右而能把窗口函数在业务场景中用对的人更少。如果说基础题是“看你会不会”那窗口函数就是“看你的思维深度”。3.1 窗口函数和GROUP BY到底差在哪窗口函数的核心特征是不改变行数每一行都能看到聚合结果。GROUP BY会把多行压成一行而窗口函数是“在保留每一行原始信息的同时额外计算出一个聚合值”。举个例子。表里有每个用户每天的消费记录你想知道“每个用户的总消费金额”以及“每一笔消费占总消费金额的比例”。用GROUP BY只能得到每个用户的总金额看不到单笔明细用窗口函数则可以SELECT user_id, order_id, amount, SUM(amount) OVER (PARTITION BY user_id) AS user_total_amount, amount / SUM(amount) OVER (PARTITION BY user_id) AS amount_ratio FROM orders;为了理解这个区别可以打个比方GROUP BY像一个漏斗把很多行倒进去出来的是一小撮精华窗口函数像一面放大镜不改变原图只是在每行旁边贴了一个计算标签。数据分析里经常遇到“既要明细又要汇总”的需求比如算占比、算累计、算同组排名这就是窗口函数的主场。窗口函数的基本语法是函数名() OVER ( PARTITION BY 分组字段 ORDER BY 排序字段 [ROWS BETWEEN 边界规则] )注意两点PARTITION BY的“分组维度”和ORDER BY的“排序维度”决定了窗口的形状ROWS BETWEEN则用来控制计算范围。绝大多数面试题只要用到PARTITION BY和ORDER BY就够但你能讲清楚窗口边界规则面试官对你的印象会明显不一样。3.2 排序三兄弟ROW_NUMBER、RANK、DENSE_RANK这是窗口函数里最经典的一组题。同样是给用户按消费金额排序这三者的区别是什么用一个简单例子说明用户消费金额ROW_NUMBERRANKDENSE_RANKA100111B100211C80332D60443ROW_NUMBER依次编号不管有没有并列RANK遇到并列会跳过编号100并列第一下一个人排第三DENSE_RANK遇到并列不跳过100并列第一下一个人排第二。面试题里最常出现的“取TOP N”需求默认用哪个我的经验是看需求强调不强调并列。如果题目说“取每个品类销量前3的商品”一般意味着最多取3条如果题目说“找出销量最高的所有商品”那就需要包含所有并列的数据。前者用ROW_NUMBER或RANK都行但要注意ROW_NUMBER在并列时会随机选一个RANK会把并列全部选出来却可能超过3条后者更保险的是用RANK或DENSE_RANK再加过滤条件。实际工作里我用得最多的还是ROW_NUMBER因为很多业务场景只需要一条“代表记录”比如“每个用户最近一次下单记录”。但面试时最好把三者区别以及适用场景都说清楚这能体现你考虑问题的周全。TopN问题的标准答法以“每个部门薪资最高的员工”为例WITH ranked_employee AS ( SELECT employee_id, employee_name, department_id, salary, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn FROM employee ) SELECT employee_id, employee_name, department_id, salary FROM ranked_employee WHERE rn 1;这段代码面试中出现频率极高建议你练到闭眼能写。注意我把排序结果单独放在CTE里再过滤而不是直接在外面套WHERE rn 1——因为WHERE的执行顺序在SELECT之前窗口函数的结果在WHERE阶段还不可见必须用子查询或CTE包一层。3.3 聚合窗口与移动计算累计值、LAG与LEAD除了排序窗口函数还经常用来算累计值比如“求每个用户截至当前日的累计消费”。这里的核心是ORDER BY与SUM窗口函数的组合只用PARTITION BY是组内汇总加上ORDER BY就变成了“随着排序逐行滚动累加”。SELECT user_id, order_date, amount, SUM(amount) OVER ( PARTITION BY user_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_amount FROM orders;ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW的意思是从分组的第一行到当前行参与计算这也是累计值running total的标准写法。实际业务里计算月度累计销售额、用户累计消费、库存滚动结余用的都是这套逻辑。LAG和LEAD是另外两个高频函数用来取前一行或后一行的值。最常见的使用场景是算同比环比。比如算每个月的环比增长率WITH monthly_sales AS ( SELECT DATE_TRUNC(month, order_date) AS month, SUM(amount) AS total_amount FROM orders GROUP BY DATE_TRUNC(month, order_date) ) SELECT month, total_amount, LAG(total_amount, 1) OVER (ORDER BY month) AS prev_month_amount, (total_amount - LAG(total_amount, 1) OVER (ORDER BY month)) / LAG(total_amount, 1) OVER (ORDER BY month) AS mom_rate FROM monthly_sales ORDER BY month;注意LAG的第二个参数表示向前几行默认是1第三个参数是取不到前一行时的默认值。如果第一个月没有前值结果会是NULL业务上可以用COALESCE处理。我面试的时候喜欢问LAG因为它能自然衔接“窗口函数 业务指标”的能力。4. 业务场景题从SQL到商业分析思维到了这个环节SQL就不再是单纯的语法题了而是真正考核数据分析师的业务抽象能力。面试官会给你一个业务问题看你能不能把它翻译成SQL。这里挑四个出现频率最高的场景拆解。4.1 留存率计算口径决定一切留存率是数据分析面试的保留题目几乎每家互联网公司的面试题里都有它的变体。题目描述一般是有一张用户活跃表包含user_id和active_date求某日新增用户的次日留存率、7日留存率等。很多人一上来就写SQL结果发现题目根本没给“新增用户”的定义。所以在动手前一定要先和面试官确认口径新增用户的定义是注册时间在某天还是首次活跃时间在某天我面试时会特意问一句看候选人会不会主动澄清。这个动作本身就占了得分点。假设口径是“某天首次活跃的用户视为该日新增用户”计算次日留存率的SQLWITH first_active AS ( SELECT user_id, MIN(active_date) AS first_date FROM user_active_log GROUP BY user_id ), active_next_day AS ( SELECT DISTINCT a.user_id, a.active_date FROM user_active_log a ) SELECT f.first_date, COUNT(DISTINCT f.user_id) AS new_user_cnt, COUNT(DISTINCT CASE WHEN n.active_date DATE_ADD(f.first_date, INTERVAL 1 DAY) THEN f.user_id END) AS retained_user_cnt, COUNT(DISTINCT CASE WHEN n.active_date DATE_ADD(f.first_date, INTERVAL 1 DAY) THEN f.user_id END) / COUNT(DISTINCT f.user_id) AS retention_rate FROM first_active f LEFT JOIN active_next_day n ON f.user_id n.user_id GROUP BY f.first_date;核心逻辑是先找到每个用户的首次活跃日期作为新增日期再用LEFT JOIN关联该用户次日是否活跃最后用COUNT DISTINCT CASE WHEN的写法来算留存人数和留存率。这道题的难点在于为什么用LEFT JOIN而不是INNER JOIN。用INNER JOIN会把次日没活跃的新增用户全部排除掉留存率分母直接少一块。另外为什么子查询里要加DISTINCT因为用户一天可能有多条活跃记录如果不先去重同一个用户会JOIN出多行COUNT DISTINCT虽然能兜底但会带来额外的计算负担。注意写留存SQL的关键并不是记住某个固定模板而是理解“新增日期”和“活跃日期”这两组时间维度的对应关系。面试中如果遇到留存、活跃、转化这类指标先画清楚时间线再写代码。4.2 复购率行为口径的拆解复购率是电商、零售行业面试的常见题。题目可能是有一张订单表包含user_id、order_id、order_date求2024年1月的复购率。复购率的口径也有两种常见理解一是“统计周期内购买2次及以上的用户数 / 总购买用户数”二是“老用户中再次购买的比例”。两种口径SQL差异不大关键是你要说清楚你采用的是哪一种。按第一种口径写WITH user_buy AS ( SELECT user_id, COUNT(DISTINCT order_id) AS buy_cnt FROM orders WHERE order_date 2024-01-01 AND order_date 2024-02-01 GROUP BY user_id ) SELECT COUNT(CASE WHEN buy_cnt 2 THEN user_id END) AS repurchase_user_cnt, COUNT(user_id) AS total_user_cnt, COUNT(CASE WHEN buy_cnt 2 THEN user_id END) / COUNT(user_id) AS repurchase_rate FROM user_buy;是不是感觉和留存率的写法很像对数据分析面试里很多题目本质上都是“分组计数 条件计数 比例计算”的排列组合。把“满足条件的用户数”和“总用户数”相互比较就出现了各种率指标。这个SQL里我用了COUNT(CASE WHEN ... THEN user_id END)它等价于SUM(CASE WHEN ... THEN 1 ELSE 0 END)。两种写法都行看个人习惯。如果user_id没有NULL值两种写法结果一样如果有NULL值SUM(CASE WHEN ... THEN 1 ELSE 0 END)更稳妥。4.3 连续登录天数经典中的经典连续登录天数这道题几乎每轮面试必考。题目通常这样给定用户登录表user_id, login_date求每个用户的历史最大连续登录天数。解题思路很巧妙核心是一句话用登录日期减去按登录日期排序得到的序号如果连续这个差值会是同一个值。举个例子。用户A在1月1日、1月2日、1月5日登录。按日期排序后它们的ROW_NUMBER分别是1、2、3。用登录日期减去编号1月1日减1等于12月31日1月2日减2等于12月31日1月5日减3等于1月2日。前两个差值相同说明这两天连续第三个差值不同说明断档了。WITH login_ranked AS ( SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY) AS diff_date FROM ( SELECT DISTINCT user_id, login_date FROM user_login_log ) t ) SELECT user_id, MAX(consecutive_days) AS max_consecutive_days FROM ( SELECT user_id, COUNT(*) AS consecutive_days FROM login_ranked GROUP BY user_id, diff_date ) a GROUP BY user_id;注意两点。第一内层子查询先做了一轮DISTINCT去重因为同一天可能有多次登录不去重的话序号会偏大导致连续日期计算错误。第二既然同一用户同一天只有一条记录那么按dif_date分组后组内行数就等于这个连续区间的天数。这道题考察的“用日期减序号识别连续区间”的思路在用户行为分析里应用非常广。比如识别连续消费用户、连续签到用户、连续活跃用户本质都是这个套路。我面试时把这个思路理解了比背答案值钱得多。4.4 同比环比LAG的实战价值同比环比在商业分析面试里也很常见尤其面业务方向的数据分析师。题目可能给你一张日/月销售额表让你计算每个月的环比增长率和同比增长率。环比就是和上个月比同比增长可以和去年同月比。用LAG可以轻松实现WITH monthly AS ( SELECT DATE_FORMAT(month, %Y-%m) AS month, SUM(sales_amount) AS sales_amount FROM sales_table GROUP BY DATE_FORMAT(month, %Y-%m) ) SELECT month, sales_amount, LAG(sales_amount, 1) OVER (ORDER BY month) AS prev_month_sales, LAG(sales_amount, 12) OVER (ORDER BY month) AS prev_year_sales, ROUND((sales_amount - LAG(sales_amount, 1) OVER (ORDER BY month)) / LAG(sales_amount, 1) OVER (ORDER BY month) * 100, 2) AS mom_growth_rate, ROUND((sales_amount - LAG(sales_amount, 12) OVER (ORDER BY month)) / LAG(sales_amount, 12) OVER (ORDER BY month) * 100, 2) AS yoy_growth_rate FROM monthly ORDER BY month;LAG(sales_amount, 12)表示往前推12个月适用于月度数据的同比。如果数据是日粒度同比就是LAG(..., 365)但要注意闰年问题实际工作中常按“去年同期同一天”特殊处理。能意识到这一点在面试中会很加分。5. 性能和规范让面试官刮目相看的细节很多候选人以为SQL题目只要结果对就可以了。其实不然。我面过不少人答案写对了但满屏SELECT *临时表建了好几个过滤条件乱放。虽然不算错但给人的印象分大打折扣。面试官心里会嘀咕这个人如果上线写接口会不会也这么草率5.1 慢SQL优化基础但不冷门热词里有“慢sql优化”这确实是数据分析师日常工作中绕不开的问题。你的SQL跑半小时业务还在等数据这体验谁受得了。面试中关于性能优化常被问到的点有避免SELECT *只查需要的字段。数据传输少解析快也方便后续维护。WHERE子句里的函数包裹会导致索引失效。比如WHERE DATE(create_time) 2024-01-01可以改成WHERE create_time 2024-01-01 AND create_time 2024-01-02。隐式类型转换同样会让索引失效。比如数字字段被写成字符串来比较或者反过来。分组前先过滤而不是分组后再过滤。WHERE过滤的行数越少后续GROUP BY和JOIN的计算量就越小。大表JOIN尽量用小表驱动大表。很多数据库优化器会自动处理但手工SQL里注意一下总没有坏处。子查询能改JOIN就改JOIN。老版本MySQL里子查询性能弱于JOIN现在优化器改进了不少但可读性上JOIN仍然更清晰。这些点你不需要背得多深入但能在写完SQL之后主动说一句“我注意到这个查询里create_time上用了函数可能索引会失效建议改成范围查询”面试官就会觉得你是真做过优化而不是只会背题。5.2 写出让面试官舒服的SQL代码风格在面试里是隐性加分项。我总结几点经验显式写明字段名不写SELECT *。这一点前面提过这里再强调一次。面试官会从你的每个字段里看出你有没有需求分析的意识。大小写和缩进保持统一。关键字大写、字段小写是我的习惯。缩进用到缩进JOIN条件对齐写清楚。代码不是写给自己看的是写给同事看的。复杂的SQL优先用CTE拆解。比起层层嵌套的子查询CTE让每一层逻辑都有名字、都能独立理解。比如前面留存率那个例子我先写first_active、再写active_next_day每一步都能看懂。面试时向面试官解释起来也顺畅很多。关键指标计算加上注释。数据分析SQL里经常出现复杂的口径计算比如“留存率 次日活跃的新增用户数 / 当日新增用户数”。在SQL开头写清楚这个口径后面再看代码的人就不会一脸懵。5.3 排查SQL错误的方法论面试现场写SQL难免写出跑不通的代码。我不怕候选人报错就怕候选人对错误毫无头绪。这里分享一个排查思路先看报错的类型。语法错误多半是括号不匹配、逗号多了少了字段名报错可能是表别名没对上分组聚合报错一般是SELECT的字段没有出现在GROUP BY里。再看结果与预期不符的情况。如果拿到结果但数字不对我建议按以下顺序排查先确认JOIN类型对不对是不是应该用LEFT JOIN却用了INNER JOIN再看过滤条件写在了ON还是WHERE然后检查空值数据尤其是NULL是否被意外过滤或计入最后检查去重逻辑JOIN是否导致数据膨胀。有一个我在工作中反复用的小技巧先跑一层子查询验证中间结果再跑完整SQL。面试时如果你觉得结果不对也别慌把中间的CTE单独拿来看一眼往往问题就暴露了。这个习惯在面试现场很能体现你的调试能力。6. 面试现场实录与避坑指南最后这部分我整理了一些面试现场的真实观察和技巧。这些都是常规准备帖里看不到的但往往是决定结果的关键细节。6.1 拿到题之后先别急着写很多人拿到题就开始敲键盘结果写了半天发现理解错了方向浪费时间也影响心态。我的建议是花30秒到1分钟确认三件事时间范围题目的统计周期是哪个时间段是日、周、月还是累计用户口径这里的“用户”是注册用户、活跃用户还是付费用户结果形式输出是按天分组还是按用户分组指标是数量、金额还是比例面试官设计题目时不可能把所有细节都写得清清楚楚。主动问清口径不仅不扣分还会让面试官觉得你有扎实的业务意识。我面试时候选人如果能把口径问到点子上我心里基本已经给这个人的业务理解打了高分。6.2 七种SQL面试高频错误错误类型典型场景正确做法JOIN后过滤条件写错位置LEFT JOIN时把右表条件写WHERE放到ON里只求结果不考虑重复JOIN导致多对多数据膨胀先看关联字段是否唯一COUNT(*)与COUNT(字段)混用字段为NULL导致计数偏少明确统计口径NULL处理不当用“ NULL”判断空值用IS NULL / IS NOT NULL窗口函数过滤直接放WHEREWHERE rn 1 报错必须包一层子查询/CTE日期函数格式不统一DATE_ADD、DATE_SUB混用统一日期处理函数GROUP BY忘记包含非聚合字段SELECT的普通字段不在GROUP BY里要么加进GROUP BY要么用ANY_VALUE/MAX等聚合6.3 面试时如何展示沟通能力SQL面试不只是写代码同时也是沟通测试。我建议你在写SQL的过程中自言自语式地向面试官同步你的思路。比如“我先建一个CTE去重拿到每个用户的首次登录日期然后再关联后续活跃记录来计算留存。”这种表达有几个好处面试官能跟上你的思路即使最后结果有小问题他也知道你的方向是对的而且遇到卡壳时面试官更容易给你提示。写完之后不要只说“写完了”可以花20秒顺一下你的逻辑“这里我用ROW_NUMBER是因为需要每组取最新一条并列情况没有影响因为只要一单最新记录空值我用COALESCE做了兜底。”这种小结既展示了代码能力也展示了沟通总结能力。7. 一份按优先级排列的备战建议如果你正在准备数据分析或商业分析方向的面试我按重要性从高到低列一个清单你可以照着查缺补漏第一优先把窗口函数练熟。排序三兄弟的区别、SUM窗口的累计用法、LAG/LEAD的环比同比这三件事几乎覆盖了八成窗口函数面试题。第二优先把经典业务场景题做一遍。留存率、复购率、连续登录天数、TopN每道题至少手写两遍做到不看参考答案也能写出来并且能说出每一步在干什么。第三优先把JOIN和去重的细节吃透。ON和WHERE的位置区别、LEFT JOIN右表条件过滤、COUNT DISTINCT的空值陷阱这几个点基础但容易翻车。第四优先练一两道完整的SQL笔试题控制时间。面试现场题量通常不小既要准确又要速度。平时可以给自己掐表20分钟模拟真实面试环境。第五优先面试前花10分钟回顾一下自己的实战SQL经验。面试官大概率会问“你最近写过最复杂的一条SQL是什么”这个问题没有标准答案但你要能用自己的实际工作案例讲清楚任务背景、SQL逻辑和最终效果。我个人在实际带人过程中的体会是SQL面试准备最怕的是“眼高手低”。看懂了不等于会写了会写了不等于能在限时和压力下写对。数据分析和商业分析岗位的发展路径越往上走对逻辑思维和业务理解的要求越高于纯语法技巧。所以建议你刷题之外多想想每道题背后的业务意义——面试官想要的从来不是一个“打字员”而是一个能通过SQL洞察业务问题的分析师。
返回列表