楼主: Myron2017
跳转到指定楼层
上一主题 下一主题
收起左侧

刷题记录帖子

🔗
 楼主| Myron2017 3 天前 | 只看该作者
全局:
615. Average Salary: Departments VS Company
Attempted
Hard
Topics
SQL Schema
Pandas Schema
Table: Salary

+-------------+------+
| Column Name | Type |
+-------------+------+
| id          | int  |
| employee_id | int  |
| amount      | int  |
| pay_date    | date |
+-------------+------+
In SQL, id is the primary key column for this table.
Each row of this table indicates the salary of an employee in one month.
employee_id is a foreign key (reference column) from the Employee table.


Table: Employee

+---------------+------+
| Column Name   | Type |
+---------------+------+
| employee_id   | int  |
| department_id | int  |
+---------------+------+
In SQL, employee_id is the primary key column for this table.
Each row of this table indicates the department of an employee.


Find the comparison result (higher/lower/same) of the average salary of employees in a department to the company's average salary.

Return the result table in any order.

The result format is in the following example.



Example 1:

Input:
Salary table:
+----+-------------+--------+------------+
| id | employee_id | amount | pay_date   |
+----+-------------+--------+------------+
| 1  | 1           | 9000   | 2017/03/31 |
| 2  | 2           | 6000   | 2017/03/31 |
| 3  | 3           | 10000  | 2017/03/31 |
| 4  | 1           | 7000   | 2017/02/28 |
| 5  | 2           | 6000   | 2017/02/28 |
| 6  | 3           | 8000   | 2017/02/28 |
+----+-------------+--------+------------+
Employee table:
+-------------+---------------+
| employee_id | department_id |
+-------------+---------------+
| 1           | 1             |
| 2           | 2             |
| 3           | 2             |
+-------------+---------------+
Output:
+-----------+---------------+------------+
| pay_month | department_id | comparison |
+-----------+---------------+------------+
| 2017-02   | 1             | same       |
| 2017-03   | 1             | higher     |
| 2017-02   | 2             | same       |
| 2017-03   | 2             | lower      |
+-----------+---------------+------------+
Explanation:
In March, the company's average salary is (9000+6000+10000)/3 = 8333.33...
The average salary for department '1' is 9000, which is the salary of employee_id '1' since there is only one employee in this department. So the comparison result is 'higher' since 9000 > 8333.33 obviously.
The average salary of department '2' is (6000 + 10000)/2 = 8000, which is the average of employee_id '2' and '3'. So the comparison result is 'lower' since 8000 < 8333.33.

With he same formula for the average salary comparison in February, the result is 'same' since both the department '1' and '2' have the same average salary with the company, which is 7000.


这道题的核心其实就两步:

算每个月公司的平均工资
算每个月每个部门的平均工资,然后比较

最容易踩的坑是:公司的平均工资必须按“员工工资记录”直接计算,不能先算部门平均再对部门平均求平均。因为每个部门的员工人数可能不同。
  1. WITH monthly_company AS (
  2.     SELECT
  3.         DATE_FORMAT(pay_date, '%Y-%m') AS pay_month,
  4.         AVG(amount) AS company_avg
  5.     FROM Salary
  6.     GROUP BY DATE_FORMAT(pay_date, '%Y-%m')
  7. ),

  8. monthly_department AS (
  9.     SELECT
  10.         DATE_FORMAT(s.pay_date, '%Y-%m') AS pay_month,
  11.         e.department_id,
  12.         AVG(s.amount) AS department_avg
  13.     FROM Salary s
  14.     JOIN Employee e
  15.         ON s.employee_id = e.employee_id
  16.     GROUP BY
  17.         DATE_FORMAT(s.pay_date, '%Y-%m'),
  18.         e.department_id
  19. )

  20. SELECT
  21.     d.pay_month,
  22.     d.department_id,
  23.     CASE
  24.         WHEN d.department_avg > c.company_avg THEN 'higher'
  25.         WHEN d.department_avg < c.company_avg THEN 'lower'
  26.         ELSE 'same'
  27.     END AS comparison
  28. FROM monthly_department d
  29. JOIN monthly_company c
  30.     ON d.pay_month = c.pay_month;
复制代码
一步一步理解
1. 公司每个月平均工资
SELECT
    DATE_FORMAT(pay_date, '%Y-%m') AS pay_month,
    AVG(amount) AS company_avg
FROM Salary
GROUP BY DATE_FORMAT(pay_date, '%Y-%m')

得到类似:

2017-02    7000
2017-03    8333.33

因为公司平均工资只和 月份 有关,所以只 GROUP BY pay_month。

2. 每个月、每个部门平均工资

需要把 Salary 和 Employee 连接起来,因为 department_id 在 Employee 表:

FROM Salary s
JOIN Employee e
    ON s.employee_id = e.employee_id

然后:

GROUP BY pay_month, department_id

得到:

2017-02   department 1   7000
2017-02   department 2   7000
2017-03   department 1   9000
2017-03   department 2   8000
3. 最后比较
CASE
    WHEN d.department_avg > c.company_avg THEN 'higher'
    WHEN d.department_avg < c.company_avg THEN 'lower'
    ELSE 'same'
END

就是:

部门平均 > 公司平均 → higher
部门平均 < 公司平均 → lower
部门平均 = 公司平均 → same
一个非常重要的错误写法

很多人会想到:

AVG(department_avg)

来计算公司的平均工资。

这是错的。

例如:

Department A: 1 employee, salary = 10,000
Department B: 9 employees, salary = 1,000

真实公司平均:

(10000 + 9 * 1000) / 10 = 1900

但如果对部门平均求平均:

(10000 + 1000) / 2 = 5500

完全不一样。

所以这题要记住:

Company AVG → 直接对 Salary.amount 求 AVG
Department AVG → JOIN Employee 后按 month + department 求 AVG
回复

使用道具 举报

🔗
 楼主| Myron2017 3 天前 | 只看该作者
全局:
614. Second Degree Follower
Medium
Topics
SQL Schema
Pandas Schema
Table: Follow

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| followee    | varchar |
| follower    | varchar |
+-------------+---------+
(followee, follower) is the primary key (combination of columns with unique values) for this table.
Each row of this table indicates that the user follower follows the user followee on a social network.
There will not be a user following themself.


A second-degree follower is a user who:

follows at least one user, and
is followed by at least one user.
Write a solution to report the second-degree users and the number of their followers.

Return the result table ordered by follower in alphabetical order.

The result format is in the following example.



Example 1:

Input:
Follow table:
+----------+----------+
| followee | follower |
+----------+----------+
| Alice    | Bob      |
| Bob      | Cena     |
| Bob      | Donald   |
| Donald   | Edward   |
+----------+----------+
Output:
+----------+-----+
| follower | num |
+----------+-----+
| Bob      | 2   |
| Donald   | 1   |
+----------+-----+
Explanation:
User Bob has 2 followers. Bob is a second-degree follower because he follows Alice, so we include him in the result table.
User Donald has 1 follower. Donald is a second-degree follower because he follows Bob, so we include him in the result table.
User Alice has 1 follower. Alice is not a second-degree follower because she does not follow anyone, so we don not include her in the result table.


核心就是准确理解 Follow 两列的含义:

followee  ← 被关注的人
follower  ← 关注别人的人

一个用户要成为 second-degree follower,必须同时满足:

他出现在 follower 列 → 他至少关注了一个人
他出现在 followee 列 → 至少有人关注他

而我们最后要统计的是:有多少人关注这个用户,所以直接对 followee 分组即可。
  1. SELECT
  2.     followee AS follower,
  3.     COUNT(*) AS num
  4. FROM Follow
  5. WHERE followee IN (
  6.     SELECT follower
  7.     FROM Follow
  8. )
  9. GROUP BY followee
  10. ORDER BY followee;
复制代码
回复

使用道具 举报

🔗
 楼主| Myron2017 3 天前 | 只看该作者
全局:
613. Shortest Distance in a Line
Easy
Topics
SQL Schema
Pandas Schema
Table: Point

+-------------+------+
| Column Name | Type |
+-------------+------+
| x           | int  |
+-------------+------+
In SQL, x is the primary key column for this table.
Each row of this table indicates the position of a point on the X-axis.


Find the shortest distance between any two points from the Point table.

It is guaranteed that the Point table contains at least two rows.

The result format is in the following example.



Example 1:

Input:
Point table:
+----+
| x  |
+----+
| -1 |
| 0  |
| 2  |
+----+
Output:
+----------+
| shortest |
+----------+
| 1        |
+----------+
Explanation: The shortest distance is between points -1 and 0 which is |(-1) - 0| = 1.


Follow up: How could you optimize your solution if the Point table is ordered in ascending order?

1. 普通解法

任意两个不同的点都可以组成一对,所以我们可以让 Point 表自己 JOIN 自己。

SELECT MIN(ABS(p1.x - p2.x)) AS shortest
FROM Point p1
JOIN Point p2
    ON p1.x != p2.x;
为什么这样就行?

假设:

-1
0
2

Self Join 后会产生:

p1    p2    distance
-1     0       1
-1     2       3
0    -1       1
0     2       2
2    -1       3
2     0       2

然后:

MIN(ABS(p1.x - p2.x))

就是:

MIN(1, 3, 1, 2, 3, 2) = 1

所以答案是 1。

2. 可以进一步优化 JOIN 条件

上面的写法其实产生了重复的 pair:

(-1, 0)
(0, -1)

它们的距离完全一样。

所以可以改成:

SELECT MIN(p2.x - p1.x) AS shortest
FROM Point p1
JOIN Point p2
    ON p1.x < p2.x;

因为:

p1.x < p2.x

保证了:

不会自己和自己比较
(A, B) 和 (B, A) 只保留一个
因为 p2.x > p1.x,所以距离直接就是 p2.x - p1.x,不需要 ABS()

这个比第一种更好。

3. Follow-up:如果 Point 已经按升序排列,怎么优化?

这是这道题真正想考的地方。

如果点已经是:

-10
-3
0
2
8

那么最短距离一定出现在相邻的两个点之间。

原因很简单:

假设有三个点:

a < b < c

那么:

c - a > b - a
c - a > c - b

所以 a 和 c 不可能比相邻点 a,b 或 b,c 更近。

因此只需要比较:

(-10, -3)
(-3, 0)
(0, 2)
(2, 8)

而不需要比较所有 pair。

SQL 可以写成
SELECT MIN(p2.x - p1.x) AS shortest
FROM Point p1
JOIN Point p2
    ON p2.x = p1.x + 1;

但是这里有一个重要问题:

这要求点的 x 值必须恰好连续,例如:

1
2
3
4

如果数据是:

-10
-3
0
2
8

那么 x + 1 显然不成立。

所以真正通用的“相邻点” SQL,应该使用 LEAD():

SELECT MIN(next_x - x) AS shortest
FROM (
    SELECT
        x,
        LEAD(x) OVER (ORDER BY x) AS next_x
    FROM Point
) t
WHERE next_x IS NOT NULL;

结果就是:

-10 → -3   = 7
-3  →  0   = 3
0  →  2   = 2
2  →  8   = 6

MIN = 2
  1. SELECT MIN(ABS(p1.x - p2.x)) AS shortest
  2. FROM Point p1
  3. JOIN Point p2
  4.     ON p1.x != p2.x;
复制代码
回复

使用道具 举报

🔗
 楼主| Myron2017 3 天前 | 只看该作者
全局:
612. Shortest Distance in a Plane
Medium
Topics
conpanies icon
Companies
SQL Schema
Pandas Schema
Table: Point2D

+-------------+------+
| Column Name | Type |
+-------------+------+
| x           | int  |
| y           | int  |
+-------------+------+
(x, y) is the primary key column (combination of columns with unique values) for this table.
Each row of this table indicates the position of a point on the X-Y plane.


The distance between two points p1(x1, y1) and p2(x2, y2) is sqrt((x2 - x1)2 + (y2 - y1)2).

Write a solution to report the shortest distance between any two points from the Point2D table. Round the distance to two decimal points.

The result format is in the following example.



Example 1:

Input:
Point2D table:
+----+----+
| x  | y  |
+----+----+
| -1 | -1 |
| 0  | 0  |
| -1 | -2 |
+----+----+
Output:
+----------+
| shortest |
+----------+
| 1.00     |
+----------+
Explanation: The shortest distance is 1.00 from point (-1, -1) to (-1, 2).

为什么 JOIN 条件这样写?

我们需要找任意两个不同的点。

如果直接:

ON p1.x != p2.x OR p1.y != p2.y

虽然也能做对,但是会产生重复:

A → B
B → A

距离完全一样。

所以我们规定一个固定顺序,只保留一份:

p1.x < p2.x
OR (p1.x = p2.x AND p1.y < p2.y)

相当于按照:

先比较 x
x 相同再比较 y

来决定谁是 p1、谁是 p2。

距离公式

题目给的是:

$$ \sqrt{(x_2-x_1)^2+(y_2-y_1)^2} $$

SQL:

SQRT(
    POW(p2.x - p1.x, 2) +
    POW(p2.y - p1.y, 2)
)

比如:

(-1,-1)
( 0, 0)
(-1,-2)

三组距离:

(-1,-1) ↔ (0,0)   = √2 ≈ 1.414
(-1,-1) ↔ (-1,-2) = 1
(0,0)   ↔ (-1,-2) = √5 ≈ 2.236

所以:

MIN(distance)

就是:

1

最后:

ROUND(..., 2)

得到:

1.00
一个容易犯的错误

不要写:

MIN(ROUND(distance, 2))

更严谨的是:

ROUND(MIN(distance), 2)

因为题目要求的是:

先找到真正的最短距离,再四舍五入到两位小数。

所以结构应该是:

所有 pair
   ↓
计算真实距离
   ↓
MIN
   ↓
ROUND(..., 2)
  1. SELECT
  2.     ROUND(
  3.         MIN(
  4.             SQRT(
  5.                 POW(p2.x - p1.x, 2) +
  6.                 POW(p2.y - p1.y, 2)
  7.             )
  8.         ),
  9.         2
  10.     ) AS shortest
  11. FROM Point2D p1
  12. JOIN Point2D p2
  13.     ON p1.x < p2.x
  14.     OR (p1.x = p2.x AND p1.y < p2.y);
复制代码
回复

使用道具 举报

🔗
 楼主| Myron2017 前天 09:42 | 只看该作者
全局:
610. Triangle Judgement
Easy
Topics
conpanies icon
Companies
SQL Schema
Pandas Schema
Table: Triangle

+-------------+------+
| Column Name | Type |
+-------------+------+
| x           | int  |
| y           | int  |
| z           | int  |
+-------------+------+
In SQL, (x, y, z) is the primary key column for this table.
Each row of this table contains the lengths of three line segments.


Report for every three line segments whether they can form a triangle.

Return the result table in any order.

The result format is in the following example.



Example 1:

Input:
Triangle table:
+----+----+----+
| x  | y  | z  |
+----+----+----+
| 13 | 15 | 30 |
| 10 | 20 | 15 |
+----+----+----+
Output:
+----+----+----+----------+
| x  | y  | z  | triangle |
+----+----+----+----------+
| 13 | 15 | 30 | No       |
| 10 | 20 | 15 | Yes      |
+----+----+----+----------+



核心条件

三个边长 x, y, z 能组成三角形,当且仅当:

x + y > z
x + z > y
y + z > x

因为三条边都可以是任意大小,所以三个条件都要满足。

不过 SQL 里可以利用一个更简单的写法:最长的边必须小于另外两边之和。
  1. SELECT
  2.     x,
  3.     y,
  4.     z,
  5.     IF(
  6.         x + y > z
  7.         AND x + z > y
  8.         AND y + z > x,
  9.         'Yes',
  10.         'No'
  11.     ) AS triangle
  12. FROM Triangle;
复制代码
优化,直接找最长边比较,
  1. SELECT
  2.     x,
  3.     y,
  4.     z,
  5.     IF(
  6.         GREATEST(x, y, z) < x + y + z - GREATEST(x, y, z),
  7.         'Yes',
  8.         'No'
  9.     ) AS triangle
  10. FROM Triangle;
复制代码
回复

使用道具 举报

🔗
 楼主| Myron2017 前天 09:46 | 只看该作者
全局:
608. Tree Node
Medium
Topics
conpanies icon
Companies
Hint
SQL Schema
Pandas Schema
Table: Tree

+-------------+------+
| Column Name | Type |
+-------------+------+
| id          | int  |
| p_id        | int  |
+-------------+------+
id is the column with unique values for this table.
Each row of this table contains information about the id of a node and the id of its parent node in a tree.
The given structure is always a valid tree.


Each node in the tree can be one of three types:

"Leaf": if the node is a leaf node.
"Root": if the node is the root of the tree.
"Inner": If the node is neither a leaf node nor a root node.
Write a solution to report the type of each node in the tree.

Return the result table in any order.

The result format is in the following example.



Example 1:


Input:
Tree table:
+----+------+
| id | p_id |
+----+------+
| 1  | null |
| 2  | 1    |
| 3  | 1    |
| 4  | 2    |
| 5  | 2    |
+----+------+
Output:
+----+-------+
| id | type  |
+----+-------+
| 1  | Root  |
| 2  | Inner |
| 3  | Leaf  |
| 4  | Leaf  |
| 5  | Leaf  |
+----+-------+
Explanation:
Node 1 is the root node because its parent node is null and it has child nodes 2 and 3.
Node 2 is an inner node because it has parent node 1 and child node 4 and 5.
Nodes 3, 4, and 5 are leaf nodes because they have parent nodes and they do not have child nodes.
Example 2:


Input:
Tree table:
+----+------+
| id | p_id |
+----+------+
| 1  | null |
+----+------+
Output:
+----+-------+
| id | type  |
+----+-------+
| 1  | Root  |
+----+-------+
Explanation: If there is only one node on the tree, you only need to output its root attributes.

这题的关键是:根据 p_id 和是否存在子节点来判断类型。

1. 判断规则

对于每一个 id:

p_id IS NULL → Root
有 p_id,并且这个 id 出现在其他节点的 p_id 中 → Inner
有 p_id,但这个 id 没有出现在任何人的 p_id 中 → Leaf

所以可以用 CASE WHEN + EXISTS。

这道题真正重要的知识点,不只是 CASE WHEN,而是:

Tree 在关系型数据库里,不需要专门的 Tree 数据结构;只要记录 node → parent node 的关系,就可以表示整棵树。
  1. # Write your MySQL query statement below
  2. SELECT
  3.     id,
  4.     CASE
  5.         WHEN p_id IS NULL THEN 'Root'
  6.         WHEN id IN (SELECT p_id FROM Tree) THEN 'Inner'
  7.         ELSE 'Leaf'
  8.     END AS type
  9. FROM Tree;
复制代码
为什么只需要 node + parent?

因为每个 node 只需要回答一个问题:

“我的 parent 是谁?”

例如:

2 → 1
3 → 1
4 → 2
5 → 2

把这些关系组合起来,整个 Tree 就自然出现了。

这其实就是数据库里非常重要的思想:

Tree → Parent-Child Relationship → Row

而不是:

Tree
├── Node
│   ├── Children
│   └── Children

这种程序里的对象结构。

这也解释了这道题为什么这么设计

题目给:

Tree(id, p_id)

然后让你判断:

Root
Inner
Leaf

其实是在训练你从 parent relationship 反推 tree structure。

逻辑就是:

p_id IS NULL
    ↓
  Root

有人把我作为 p_id
    ↓
  有 child
    ↓
  Inner

没人把我作为 p_id
    ↓
  没有 child
    ↓
  Leaf

所以我会把 608 Tree Node 记成:

SQL Tree 的基本表示方法:每一行存 node_id + parent_id,整个树就被表示出来了。
回复

使用道具 举报

🔗
 楼主| Myron2017 昨天 09:45 | 只看该作者
全局:
1050. Actors and Directors Who Cooperated At Least Three Times
Easy
Topics
conpanies icon
Companies
SQL Schema
Pandas Schema
Table: ActorDirector

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| actor_id    | int     |
| director_id | int     |
| timestamp   | int     |
+-------------+---------+
timestamp is the primary key (column with unique values) for this table.


Write a solution to find all the pairs (actor_id, director_id) where the actor has cooperated with the director at least three times.

Return the result table in any order.

The result format is in the following example.



Example 1:

Input:
ActorDirector table:
+-------------+-------------+-------------+
| actor_id    | director_id | timestamp   |
+-------------+-------------+-------------+
| 1           | 1           | 0           |
| 1           | 1           | 1           |
| 1           | 1           | 2           |
| 1           | 2           | 3           |
| 1           | 2           | 4           |
| 2           | 1           | 5           |
| 2           | 1           | 6           |
+-------------+-------------+-------------+
Output:
+-------------+-------------+
| actor_id    | director_id |
+-------------+-------------+
| 1           | 1           |
+-------------+-------------+
Explanation: The only pair is (1, 1) where they cooperated exactly 3 times.
  1. SELECT
  2.     actor_id,
  3.     director_id
  4. FROM ActorDirector
  5. GROUP BY actor_id, director_id
  6. HAVING COUNT(*) >= 3;
复制代码
回复

使用道具 举报

🔗
 楼主| Myron2017 昨天 09:48 | 只看该作者
全局:
1045. Customers Who Bought All Products
Medium
Topics
conpanies icon
Companies
SQL Schema
Pandas Schema
Table: Customer

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| customer_id | int     |
| product_key | int     |
+-------------+---------+
This table may contain duplicates rows.
customer_id is not NULL.
product_key is a foreign key (reference column) to Product table.


Table: Product

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| product_key | int     |
+-------------+---------+
product_key is the primary key (column with unique values) for this table.


Write a solution to report the customer ids from the Customer table that bought all the products in the Product table.

Return the result table in any order.

The result format is in the following example.



Example 1:

Input:
Customer table:
+-------------+-------------+
| customer_id | product_key |
+-------------+-------------+
| 1           | 5           |
| 2           | 6           |
| 3           | 5           |
| 3           | 6           |
| 1           | 6           |
+-------------+-------------+
Product table:
+-------------+
| product_key |
+-------------+
| 5           |
| 6           |
+-------------+
Output:
+-------------+
| customer_id |
+-------------+
| 1           |
| 3           |
+-------------+
Explanation:
The customers who bought all the products (5 and 6) are customers with IDs 1 and 3.
  1. SELECT customer_id
  2. FROM Customer
  3. GROUP BY customer_id
  4. HAVING COUNT(DISTINCT product_key) = (
  5.     SELECT COUNT(*)
  6.     FROM Product
  7. );
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表