1. 先把题面翻译成表关系:一通电话到底算给哪个国家
LeetCode 1501 这道题,我在带人刷 SQL 的时候经常拿来当“JOIN 之后到底会变成几行”的教学案例。它表面上是让找满足条件的国家,实际上考的是你能否把一个业务描述准确翻译成多表关联,然后再用聚合函数做一次组间比较。题目本身不算长,但很多人会卡在这种地方:Person 表里有国家区号,Country 表里有国家码,Calls 表里只有用户 id,那这个“国家”到底要怎么从用户表里带出来?
先把表结构理一遍。
sql复制Person(
id INT,
name VARCHAR,
phone_number VARCHAR
)
Country(
name VARCHAR,
country_code VARCHAR
)
Calls(
caller_id INT,
callee_id INT,
duration INT
)
Country 表里的 country_code 是国家区号。Person 表里的 phone_number 是带区号的完整电话号码,例如 52-55-1234-5678,前面那一段就对应墨西哥的 52。Calls 表记录了一次通话请求,caller_id 是主叫方用户,callee_id 是被叫方用户,duration 是通话秒数。
为了后面方便验证,我给出一组精简但能说明问题的数据。
| Person.id | Person.name | Person.phone_number |
|---|---|---|
| 1 | Alice | 1-312-555-0100 |
| 2 | Bob | 52-55-1234-5678 |
| 3 | Carol | 44-20-7946-0958 |
| Country.name | Country.country_code |
|---|---|
| USA | 1 |
| Mexico | 52 |
| UK | 44 |
| Calls.caller_id | Calls.callee_id | Calls.duration |
|---|---|---|
| 1 | 2 | 100 |
| 2 | 3 | 20 |
题目要求的“可以放心投资的国家”,翻译成 SQL 逻辑就是:
找到所有国家,这些国家用户参与的通话时长平均值,要严格大于全表所有通话时长的平均值。
注意这里不是说单次通话大于全局平均,而是要按国家分组之后,再对组内通话时长取平均。
在这个例子里,全球平均通话时长是 (100 + 20) / 2 = 60。
美国的 Alice 只参与了第一通电话,通话时长 100,所以美国平均时长是 100。墨西哥的 Bob 第一通电话作为被叫花了 100 秒,第二通电话作为主叫花了 20 秒,平均时长是 (100 + 20) / 2 = 60。英国的 Carol 只参与了第二通电话,平均时长是 20。
严格大于全球平均 60 的,只有美国,所以结果应该是:
| country
