SQL 基础与核心考点
在全栈面试中,虽然现代开发普遍使用 ORM 极大地简化了数据库操作,但原生 SQL 能力依然是考察候选人数据库基本功的核心指标。即使是前端/Node.js 全栈工程师,也必须熟练掌握复杂 SQL 的编写与底层执行逻辑。
SQL 语言的四大分类
- DDL (数据定义语言):
CREATE,ALTER,DROP,TRUNCATE(用于操作表结构)。 - DML (数据操作语言):
INSERT,UPDATE,DELETE(用于操作表数据)。 - DQL (数据查询语言):
SELECT(核心,也是面试重点)。 - DCL (数据控制语言):
GRANT,REVOKE(用于权限控制)。
必考:JOIN 连接查询
面试题:LEFT JOIN、RIGHT JOIN 和 INNER JOIN 的区别是什么?
在多表关联查询中,JOIN 是最基础的操作:
- INNER JOIN (内连接):只返回两张表中完全匹配的行。
- LEFT JOIN (左连接):返回左表的所有行。如果右表中没有匹配的数据,则右表的部分用
NULL填充。 - RIGHT JOIN (右连接):返回右表的所有行。如果没有匹配,左表部分用
NULL填充。 - FULL JOIN (全外连接):返回左表和右表的所有行,任一边没有匹配都补
NULL。(注意:MySQL 原生不支持 FULL JOIN,通常用LEFT JOIN UNION RIGHT JOIN来实现)。
聚合查询与分组 (GROUP BY & HAVING)
面试题:
WHERE和HAVING有什么区别?
WHERE:在数据分组前进行过滤,不能在 WHERE 中使用聚合函数(如SUM,COUNT,AVG)。HAVING:在数据分组后对结果集进行过滤,通常配合聚合函数使用。
-- 查询平均薪资大于 10000 的部门
SELECT department_id, AVG(salary) as avg_salary
FROM employees
WHERE status = 'active' -- 分组前:只统计在职员工
GROUP BY department_id
HAVING AVG(salary) > 10000; -- 分组后:过滤出平均薪资大于一万的部门
SQL 的执行顺序(核心理论)
面试题:你了解 SQL 语句底层的执行顺序吗?
在编写复杂 SQL 时,理解它的底层解析顺序非常重要。SQL 的书写顺序与实际引擎的执行顺序是不同的:
FROM:确定要查询的表。JOIN / ON:处理表连接及连接条件。WHERE:对连接后的数据进行行级过滤。GROUP BY:对数据进行分组。HAVING:对分组后的结果进行过滤。SELECT:选择要返回的列(此时才计算列的别名、执行投影函数)。ORDER BY:排序。LIMIT / OFFSET:分页与限制返回行数。
易错点:因为 SELECT 阶段在 WHERE 和 GROUP BY 之后执行,所以在 WHERE 子句中不能使用 SELECT 里定义的列别名!
进阶:窗口函数 (Window Functions)
在复杂的数据分析和中高级面试中,窗口函数几乎是必考题。它允许你在不合并行的情况下,执行跨行计算(MySQL 8.0+ / PostgreSQL 均支持)。
经典面试题:请写出查询“每个部门薪资前三名的员工”的 SQL。
如果不用窗口函数,这道题用原生 SQL 写极其复杂。使用 ROW_NUMBER() 或 DENSE_RANK() 则非常清晰:
SELECT * FROM (
SELECT
id,
name,
department_id,
salary,
-- 按照 department_id 分组,在组内按 salary 降序进行排名
DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) as rank
FROM employees
) AS ranked_employees
WHERE rank <= 3;
窗口函数解析:
PARTITION BY:类似于GROUP BY,它定义了排名的“窗口”(按部门划分)。ORDER BY:在窗口内按薪资降序排列。DENSE_RANK():计算排名。它的特点是如果两人薪资并列第一,下一个名次依然是第二名(1, 1, 2);而普通的RANK()下一个名次会是第三名(1, 1, 3)。