力扣高频 SQL 50 题阶段总结(一)

对应题号: 1757 / 584 / 595 / 1148 / 1683 / 1378 / 1068 / 1581 / 197 / 1661 / 577 / 1280 / 570 / 1934

本文特点:

  • 题目描述写到“读完就能自己复述题意”

  • 思路部分强调:为什么要这么设计 SQL 结构

  • 面向:后端面试 + SQL 系统复健


一、整体说明:这 14 题在训练什么?

这 14 题并不是随意排列,而是在 循序渐进地训练你 4 类核心能力

  1. 条件过滤能力(WHERE 语义)

  2. 多表关系建模能力(JOIN 思维)

  3. 统计与聚合能力(GROUP BY / COUNT / AVG)

  4. 对 NULL 的正确理解(SQL 面试分水岭)

如果你能完整吃透这 14 题,说明你已经具备:

👉 “看到业务描述,能快速拆成 SQL 结构”的能力


1️⃣ 1757. 可回收且低脂的产品

📌 题目详细描述

给定一张 Products 表,每一行代表一个产品:

  • low_fats 表示是否为低脂产品(Y / N)

  • recyclable 表示是否可回收(Y / N)

要求:找出同时满足「低脂」且「可回收」的产品编号

💡 解题思路(为什么这么写)

  • 这是一个典型的“多条件筛选”问题

  • 所有条件都来自同一张表,不涉及统计、不涉及关联

  • 在 SQL 中:

    • 同时满足多个条件 → AND

✅ 标准解法

SELECT product_id
FROM Products
WHERE low_fats = 'Y'
  AND recyclable = 'Y';


2️⃣ 584. 寻找用户推荐人

📌 题目详细描述

Customer 表中:

  • 每个用户可能有一个推荐人 referee_id

  • 也可能没有推荐人(值为 NULL

要求:找出推荐人不是 id = 2 的所有用户姓名

💡 解题思路

这道题的关键不在逻辑,而在 SQL 对 NULL 的处理规则

  • NULL != 2 的结果是 UNKNOWN,不是 TRUE

  • 所以:

    • 想保留 NULL 行,必须显式判断

✅ 正确解法

SELECT name
FROM Customer
WHERE referee_id != 2
   OR referee_id IS NULL;

⚠️ 面试高频陷阱

-- 这样写会漏掉 referee_id 为 NULL 的用户
WHERE referee_id != 2;


3️⃣ 595. 大的国家

📌 题目详细描述

World 表中包含国家的人口和面积。

要求:筛选出满足以下任一条件的国家

  • 面积 ≥ 300 万

  • 人口 ≥ 2500 万

💡 解题思路

  • 这是一个**“或条件过滤”**问题

  • 不需要统计、不需要排序

SELECT name, population, area
FROM World
WHERE area >= 3000000
   OR population >= 25000000;


4️⃣ 1148. 文章浏览 I

📌 题目详细描述

Views 表中记录了:

  • 谁是文章作者

  • 谁浏览了文章

要求:

  • 找出 作者自己浏览自己文章 的作者 id

  • 结果 去重,并按 id 升序排序

💡 解题思路

  • 条件:author_id = viewer_id

  • 同一作者可能多次浏览 → 需要去重

SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY id;


5️⃣ 1683. 无效推文

📌 题目详细描述

Tweets 表中存储推文内容。

要求:找出内容长度严格大于 15 的推文 id

💡 解题思路

  • 涉及字符串长度判断

  • 使用 SQL 内置字符串函数

SELECT tweet_id
FROM Tweets
WHERE LENGTH(content) > 15;


6️⃣ 1378. 使用唯一标识码替换员工ID

📌 题目详细描述

有两张表:

  • Employees:所有员工

  • EmployeeUNI:部分员工的唯一标识码

要求:

  • 输出所有员工姓名

  • 如果员工有唯一标识码则显示,否则显示 NULL

💡 解题思路

  • 员工必须全部保留

  • 是否有唯一标识码是“可选信息”

  • 主表是 Employees → 使用 LEFT JOIN

SELECT e.name, u.unique_id
FROM Employees e
LEFT JOIN EmployeeUNI u
ON e.id = u.id;


7️⃣ 1068. 产品销售分析 I

📌 题目详细描述

  • Sales 表记录销售行为

  • Product 表记录产品名称

要求:输出每一条销售记录对应的:

  • 产品名称

  • 销售年份

  • 价格

💡 解题思路

  • 每条销售都要保留

  • 产品信息是附加信息

SELECT p.product_name, s.year, s.price
FROM Sales s
LEFT JOIN Product p
ON s.product_id = p.product_id;


8️⃣ 1581. 进店却未进行过交易的顾客

📌 题目详细描述

  • Visits 表:顾客进店记录

  • Transactions 表:交易记录

要求:

  • 找出 有进店但没有对应交易 的顾客

  • 并统计每个顾客“未交易的进店次数”

💡 解题思路

  1. Visits 为主表(进店一定发生)

  2. LEFT JOIN 交易表

  3. 没交易 → 右表字段为 NULL

  4. 按顾客分组统计

SELECT v.customer_id, COUNT(v.visit_id) AS count_no_trans
FROM Visits v
LEFT JOIN Transactions t
ON v.visit_id = t.visit_id
WHERE t.transaction_id IS NULL
GROUP BY v.customer_id;

9️⃣ 197. 上升的温度

📌 题目详细描述

Weather 表记录每天的温度。

要求:找出那些 比前一天温度更高 的记录 id。

💡 解题思路

  • 需要把“今天”和“昨天”放在同一行比较

  • 使用 表自身 JOIN(自连接)

SELECT w1.id
FROM Weather w1
JOIN Weather w2
ON DATEDIFF(w1.recordDate, w2.recordDate) = 1
AND w1.temperature > w2.temperature;


🔟 1661. 每台机器的进程平均运行时间

📌 题目详细描述

同一台机器、同一进程有两条记录:

  • start

  • end

要求:

  • 计算每台机器的 平均运行时间

💡 解题思路

  • start / end 成对出现

  • 自连接同一张表

  • 聚合求平均

SELECT machine_id,
ROUND(AVG(end_t.timestamp - start_t.timestamp), 3) AS processing_time
FROM Activity start_t
JOIN Activity end_t
ON start_t.machine_id = end_t.machine_id
AND start_t.process_id = end_t.process_id
AND start_t.activity_type = 'start'
AND end_t.activity_type = 'end'
GROUP BY machine_id;


1️⃣1️⃣ 577. 员工奖金

📌 题目详细描述

  • 有些员工没有奖金记录

  • 要找出奖金 < 1000 或没有奖金的员工

💡 解题思路

  • 员工必须保留

  • 奖金是可选信息

SELECT e.name, b.bonus
FROM Employee e
LEFT JOIN Bonus b
ON e.empId = b.empId
WHERE b.bonus < 1000 OR b.bonus IS NULL;


1️⃣2️⃣ 1280. 学生们参加各科测试的次数

📌 题目详细描述

要求输出:

  • 每个学生

  • 每一门科目

  • 该学生参加该科目的考试次数(可能为 0)

💡 解题思路

  • 学生 × 科目 → 必须全覆盖

  • 使用 CROSS JOIN

  • 再 LEFT JOIN 考试记录

SELECT s.student_id, s.student_name, sub.subject_name,
       COUNT(e.subject_name) AS attended_exams
FROM Students s
CROSS JOIN Subjects sub
LEFT JOIN Examinations e
ON s.student_id = e.student_id
AND sub.subject_name = e.subject_name
GROUP BY s.student_id, sub.subject_name;


1️⃣3️⃣ 570. 至少有 5 名直接下属的经理

📌 题目详细描述

Employee 表中:

  • 每个员工有一个 managerId

要求:找出 直接下属数量 ≥ 5 的经理姓名

💡 解题思路

  • 员工表自连接

  • 按经理分组

  • 使用 HAVING 过滤聚合结果

SELECT m.name
FROM Employee e
JOIN Employee m
ON e.managerId = m.id
GROUP BY m.id
HAVING COUNT(e.id) >= 5;


1️⃣4️⃣ 1934. 确认率

📌 题目详细描述

  • 每个用户都注册(Signups)

  • 不一定有确认记录(Confirmations)

确认率定义为:

confirmed 次数 / 总请求次数

💡 解题思路

  • 用户必须全保留 → LEFT JOIN

  • confirmed 是条件计数

SELECT s.user_id,
ROUND(COUNT(c.action) / COUNT(s.user_id), 2) AS confirmation_rate
FROM Signups s
LEFT JOIN Confirmations c
ON s.user_id = c.user_id
AND c.action = 'confirmed'
GROUP BY s.user_id;


📌 终极总结

完成这 14 题,你已经系统掌握:

  • 条件过滤(WHERE)

  • 多表关联(LEFT JOIN / 自连接)

  • NULL 语义

  • 聚合统计(COUNT / AVG / HAVING)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值