抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

练习leetcode上高频sql50题,主要是记录思路的分析过程

四、排序和分组

619. 只出现一次的最大数字

🔹1. 理解题目目标

我们要找出:

在表中只出现一次的那些数字中,最大的那个。

关键点:

  • 「只出现一次」 ⇒ 意味着要 统计每个数字出现的次数
  • 「最大的」 ⇒ 在只出现一次的数里,取 最大值
  • 「如果不存在这样的数字」 ⇒ 返回 NULL

🔹2. 涉及的 SQL 技术

功能 SQL 技术
统计每个数字出现的次数 GROUP BY num + COUNT(*)
只保留出现一次的 HAVING COUNT(*) = 1
找出最大值 MAX()
处理空值情况 默认 MAX() 返回 NULL 如果没结果,所以不需要特别处理

🔹3. 拆解步骤

Step 1:统计每个 num 出现的次数

1
2
3
4
5
6
7
sql


复制编辑
SELECT num, COUNT(*) AS cnt
FROM MyNumbers
GROUP BY num;

Step 2:只保留那些只出现一次的数字

1
2
3
4
5
6
7
8
sql


复制编辑
SELECT num
FROM MyNumbers
GROUP BY num
HAVING COUNT(*) = 1;

Step 3:在只出现一次的数字中,找出最大值

1
2
3
4
5
6
7
8
9
10
11
sql


复制编辑
SELECT MAX(num) AS num
FROM (
SELECT num
FROM MyNumbers
GROUP BY num
HAVING COUNT(*) = 1
) AS unique_nums;

✅ 最终 SQL 答案:

1
2
3
4
5
6
7
8
9
10
11
sql


复制编辑
SELECT MAX(num) AS num
FROM (
SELECT num
FROM MyNumbers
GROUP BY num
HAVING COUNT(*) = 1
) AS unique_nums;

1045. 买下所有产品的客户

🔹1. 题目目标:

我们需要找出:

那些 在 Customer 表中,购买了 Product 表中所有产品customer_id

换句话说:

  • 找出 “全集匹配” 的客户。
  • 就是说:某个 customer_id其购买的产品集合 == Product 表中所有的产品集合

✅ 技术点分析

需要哪些 SQL 技术点?

需求 SQL 技术
产品总数 SELECT COUNT(*) FROM Product
每位客户买了多少不同产品 GROUP BY customer_id + COUNT(DISTINCT product_key)
只保留那些买的产品数 == 产品总数的客户 HAVING COUNT(DISTINCT product_key) = 产品总数

✅ 分步骤构造思路


🔸 第一步:统计 Product 表中总共有多少种产品

1
SELECT COUNT(*) FROM Product;

例如,如果结果是 3 种产品,那么我们就要找出那些买了 3 种不同产品 的客户。


🔸 第二步:统计每位客户买了多少种不同产品

注意这里要用DISTINCT,因为可能一个用户重复买了某个产品多次

1
2
3
SELECT customer_id, COUNT(DISTINCT product_key) AS product_count
FROM Customer
GROUP BY customer_id;

🔸 第三步:只保留那些 product_count = 产品总数 的客户

我们需要把产品总数用子查询或 CTE 引入进来。


✅ 最终 SQL 答案(推荐写法)

1
2
3
4
5
6
SELECT customer_id
FROM Customer
GROUP BY customer_id
HAVING COUNT(DISTINCT product_key) = (
SELECT COUNT(*) FROM Product
);

✅ 解题小结

步骤 说明
1️⃣ GROUP BY 分组每个客户
2️⃣ COUNT(DISTINCT product_key) 统计他买了多少种产品
3️⃣ HAVING 只保留买的产品数 == 总产品数的客户
4️⃣ 子查询 SELECT COUNT(*) FROM Product 用来获取总产品种类

五、高级查询和连接

1731. 每位经理的下属员工数量

这是一个很经典的自连接(self join)分析题。我们一起来逐步分析它的思路和该怎么写 SQL。


✅ 题目目标总结

我们要找出:

所有有下属的经理(即:别人的 reports_to 指向他),并返回:

  • employee_id(经理ID)
  • name(经理名字)
  • 有多少人向他汇报(直接下属数量)
  • 这些下属的平均年龄(四舍五入)

并按 employee_id 升序排序。


✅ 步骤分析


🔹1. 明确谁是“经理”

我们要找的经理,是那些 在别人 reports_to 字段中被提及过的员工,即:

1
SELECT DISTINCT reports_to FROM Employees WHERE reports_to IS NOT NULL

也就是被别人汇报的员工。


🔹2. 自连接:员工汇报给谁?

我们需要将员工表自连接,将汇报者和他们的经理连接起来:

1
2
3
4
5
6
7
SELECT 
m.employee_id AS manager_id,
m.name AS manager_name,
e.employee_id AS subordinate_id,
e.age AS subordinate_age
FROM Employees e
JOIN Employees m ON e.reports_to = m.employee_id

这样可以找出:谁向谁汇报,以及下属的年龄。


🔹3. 聚合:按经理分组统计下属人数和平均年龄

在上面的结果基础上:

  • COUNT(*) 统计每个经理的直接下属人数
  • AVG(e.age) 求下属的平均年龄
  • ROUND() 函数对平均年龄四舍五入

✅ 最终 SQL 语句如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT 
m.employee_id,
m.name,
COUNT(e.employee_id) AS reports_count,
ROUND(AVG(e.age)) AS average_age
FROM
Employees e
JOIN
Employees m ON e.reports_to = m.employee_id
GROUP BY
m.employee_id, m.name
ORDER BY
m.employee_id;

1789. 员工的直属部门

✅ 一、如何分析这道题的思路?

🔍 表示什么?

  • 一个员工(employee_id)可能在多个部门(department_id
  • 但他必须有一个直属部门
    • 如果 primary_flag = 'Y' → 说明明确标出了哪个是直属
    • 如果他只有一个部门,即使 primary_flag = 'N',这个部门仍视为直属部门

✅ 所以要做两件事:

① 找出所有 primary_flag = 'Y' 的员工部门记录(明确标记的)

② 再找出那些只在一个部门的员工(即 COUNT(department_id) = 1),他们即使标的是 'N',也认定是直属部门

最后,把这两部分数据合并UNION

❌ 二、你写的 SQL 为什么错了?

你写的两个 SQL 语法上都有结构性错误。我们看一下你写的:

1
2
3
4
5
6
7
8
9
SELECT
employee_id,
department_id
FROM
Employee
GROUP BY
employee_id
WHERE
COUNT(department_id) = 1 || primary_flag = 'Y';

❌ 错误1:GROUP BY 必须在 WHERE 之后

SQL 执行顺序中,WHERE 是用来过滤原始数据行的,而 GROUP BY 是在过滤后分组

你不能在 WHERE 中使用聚合函数 COUNT(),因为它在 GROUP BY 之后才生效。

应该写成:

1
2
GROUP BY ...
HAVING COUNT(...) ...

❌ 错误2:|| 是不合法的 SQL 运算符

SQL 中布尔 “或” 是 OR,不是 ||

所以这句也错了:

1
WHERE count(...) = 1 || primary_flag = 'Y';

❌ 错误3:逻辑错误

即使语法都对了,把 COUNT(department_id) = 1 OR primary_flag = 'Y' 写在一起也不合理,因为:

  • COUNT() 是分组聚合函数(整体层面)
  • primary_flag 是行级属性(行层面)

这两个逻辑不能混用在一个 HAVING 里。

✅ 三、正确写法(推荐用 UNION)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 第一部分:明确标记直属的
SELECT employee_id, department_id
FROM Employee
WHERE primary_flag = 'Y'

UNION

-- 第二部分:没有标Y,但这个员工只有一个部门(即自动认定为直属)
SELECT employee_id, department_id
FROM Employee
WHERE employee_id IN (
SELECT employee_id
FROM Employee
GROUP BY employee_id
HAVING COUNT(*) = 1
);

评论