目录
题目和要求
表 Person:
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| id | int |
| name | varchar |
| phone_number | varchar |
+----------------+---------+
id 是该表具有唯一值的列.
该表每一行包含一个人的名字和电话号码.
电话号码的格式是:'xxx-yyyyyyy', 其中 xxx 是国家码(3 个字符), yyyyyyy 是电话号码(7 个字符), x 和 y 都表示数字. 同时, 国家码和电话号码都可以包含前导 0.
表 Country:
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| name | varchar |
| country_code | varchar |
+----------------+---------+
country_code 是该表具有唯一值的列.
该表每一行包含国家名和国家码. country_code 的格式是'xxx', x 是数字.
表 Calls:
+-------------+------+
| Column Name | Type |
+-------------+------+
| caller_id | int |
| callee_id | int |
| duration | int |
+-------------+------+
该表无主键, 可能包含重复行.
每一行包含呼叫方 id, 被呼叫方 id 和以分钟为单位的通话时长. caller_id != callee_id
一家电信公司想要投资新的国家。该公司想要投资的国家是: 该国的平均通话时长要严格地大于全球平均通话时长。
写一个解决方案, 找到所有该公司可以投资的国家。
返回的结果表 无顺序要求。
结果格式如下例所示。
示例 1:
输入:
Person 表:
+----+----------+--------------+
| id | name | phone_number |
+----+----------+--------------+
| 3 | Jonathan | 051-1234567 |
| 12 | Elvis | 051-7654321 |
| 1 | Moncef | 212-1234567 |
| 2 | Maroua | 212-6523651 |
| 7 | Meir | 972-1234567 |
| 9 | Rachel | 972-0011100 |
+----+----------+--------------+
Country 表:
+----------+--------------+
| name | country_code |
+----------+--------------+
| Peru | 051 |
| Israel | 972 |
| Morocco | 212 |
| Germany | 049 |
| Ethiopia | 251 |
+----------+--------------+
Calls 表:
+-----------+-----------+----------+
| caller_id | callee_id | duration |
+-----------+-----------+----------+
| 1 | 9 | 33 |
| 2 | 9 | 4 |
| 1 | 2 | 59 |
| 3 | 12 | 102 |
| 3 | 12 | 330 |
| 12 | 3 | 5 |
| 7 | 9 | 13 |
| 7 | 1 | 3 |
| 9 | 7 | 1 |
| 1 | 7 | 7 |
+-----------+-----------+----------+
输出:
+----------+
| country |
+----------+
| Peru |
+----------+
解释:
国家 Peru 的平均通话时长是 (102 + 102 + 330 + 330 + 5 + 5) / 6 = 145.666667
国家 Israel 的平均通话时长是 (33 + 4 + 13 + 13 + 3 + 1 + 1 + 7) / 8 = 9.37500
国家 Morocco 的平均通话时长是 (33 + 4 + 59 + 59 + 3 + 7) / 6 = 27.5000
全球平均通话时长 = (2 * (33 + 4 + 59 + 102 + 330 + 5 + 13 + 3 + 1 + 7)) / 20 = 55.70000
所以, Peru 是唯一的平均通话时长大于全球平均通话时长的国家, 也是唯一的推荐投资的国家.
1. 题目代码
Create table If Not Exists Person (id int, name varchar(15), phone_number varchar(11));
Create table If Not Exists Country (name varchar(15), country_code varchar(3));
Create table If Not Exists Calls (caller_id int, callee_id int, duration int);
insert into Person (id, name, phone_number) values ('3', 'Jonathan', '051-1234567');
insert into Person (id, name, phone_number) values ('12', 'Elvis', '051-7654321');
insert into Person (id, name, phone_number) values ('1', 'Moncef', '212-1234567');
insert into Person (id, name, phone_number) values ('2', 'Maroua', '212-6523651');
insert into Person (id, name, phone_number) values ('7', 'Meir', '972-1234567');
insert into Person (id, name, phone_number) values ('9', 'Rachel', '972-0011100');
Truncate table Country;
insert into Country (name, country_code) values ('Peru', '051');
insert into Country (name, country_code) values ('Israel', '972');
insert into Country (name, country_code) values ('Morocco', '212');
insert into Country (name, country_code) values ('Germany', '049');
insert into Country (name, country_code) values ('Ethiopia', '251');
insert into Calls (caller_id, callee_id, duration) values ('1', '9', '33');
insert into Calls (caller_id, callee_id, duration) values ('2', '9', '4');
insert into Calls (caller_id, callee_id, duration) values ('1', '2', '59');
insert into Calls (caller_id, callee_id, duration) values ('3', '12', '102');
insert into Calls (caller_id, callee_id, duration) values ('3', '12', '330');
insert into Calls (caller_id, callee_id, duration) values ('12', '3', '5');
insert into Calls (caller_id, callee_id, duration) values ('7', '9', '13');
insert into Calls (caller_id, callee_id, duration) values ('7', '1', '3');
insert into Calls (caller_id, callee_id, duration) values ('9', '7', '1');
insert into Calls (caller_id, callee_id, duration) values ('1', '7', '7');
2. 解题思路流程图分析1 - 方法1
2. 解题思路流程图分析2 - 方法2
3. 解题思路流程图分析1 - 方法1
3. 解题思路流程图分析2 - 方法2
4. 难点分析
本题的难点主要在于:
- 多表连接:需要同时连接
Calls
、Person
和Country
三个表,确保正确匹配通话双方的国家代码。 - 数据转换与提取:从电话号码中提取国家代码部分,并将其与
Country
表中的国家代码进行匹配。 - 聚合与条件筛选:计算每个国家的平均通话时长,并与全局的平均通话时长进行比较,筛选出满足条件的国家。
- 优化查询性能:避免使用笛卡尔积等低效的查询方式,尤其在数据量大的情况下,确保查询的高效性。
5. 答案代码
-- 方法1 avg条件
with a1 as (
select left(phone_number,3) country_code -- 字符截取从左开始,截取3个,eg:left('asdf',3)=asd
from Calls c
left join Person p on c.caller_id=p.id or p.id=c.callee_id-- 因为只关心Calls中的数据,所以left join 更为严谨
group by left(phone_number,3)
having avg(case when id in (caller_id and callee_id) then duration
when id in (caller_id and callee_id) then duration
else duration end)>(select avg(duration) from Calls) )
-- 这里只能用case when,一开始我是用avg(if( id in (caller_id and callee_id),duration*2,duration))虽然提交都能通过(有时候力扣测试案例不全面,需自己多思考)
-- 但是我后思发现用avg(if())算出来的Morocco=44.5000不是27.5000 (用窗口函数验证出来的)
-- 这是因为duration*2或者duration+duration,被avg视为一个整体,即每次少一个分母个数
select name country
from Country c
join a1 on a1.country_code=c.country_code;
-- 方法2 重构表 left join
select c.name country
from
(select caller_id as call_id, duration from Calls
union all
select callee_id as call_id, duration from Calls) as a
left join Person p on p.id=a.call_id-- 因为只关心Calls中的数据,所以left join 更为严谨
left join Country c on c.country_code=left(p.phone_number,3)
group by c.name
having avg(duration)> (select avg(duration) from Calls);
# 下面还有一个笛卡尔积的方法,虽然短但是非常不推荐,因为这么写笛卡尔积要把数据库炸了,实际生产环境中通话记录、用户数的数据量肯定巨大
# SELECT c.name AS country
# FROM Calls, Person, Country c
# WHERE (caller_id = id OR callee_id = id) AND country_code = LEFT(phone_number, 3)
# GROUP BY country_code
# HAVING AVG(duration) > (SELECT AVG(duration) FROM Calls);
6. 关键总结
要掌握本题的关键知识点包括:
- 多表连接(JOIN):熟练使用
JOIN
进行多表数据的关联,特别是LEFT JOIN
在确保数据完整性方面的重要性。 - 字符串处理函数:如
LEFT()
,用于从电话号码中提取国家代码部分。 - 聚合函数与分组(GROUP BY):能够按特定字段分组数据,并应用聚合函数如
AVG()
进行计算。 - 子查询:在
HAVING
子句中使用子查询来计算全局的平均值,以便进行比较筛选。 - 条件表达式:如
IF()
函数,用于根据特定条件调整计算逻辑。 - CTE(公用表表达式):使用
WITH
语句简化复杂查询,提升代码的可读性和维护性。 - 性能优化:理解为什么某些查询方式(如笛卡尔积)在大数据量情况下效率低下,学会选择更高效的查询策略。
通过以上知识点的掌握,可以有效解决类似的复杂SQL查询问题。
标签:10,Calls,insert,1501,三种,2023,duration,放心,id From: https://blog.csdn.net/weixin_74002941/article/details/143109369