题目描述

(通过次数8,868 | 提交次数11,509,通过率77.05%)

表:Calls
+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| from_id     | int     |
| to_id       | int     |
| duration    | int     |
+-------------+---------+
该表没有主键,可能存在重复项。
该表包含 from_id 与 to_id 间的一次电话的时长。
from_id != to_id
编写 SQL 语句,查询每一对用户(person1, person2)之间的通话次数和通话总时长,其中person1 < person2。
以 任意顺序 返回结果表。
查询结果格式如下示例所示。
示例 1:
输入:
Calls 表:
+---------+-------+----------+
| from_id | to_id | duration |
+---------+-------+----------+
| 1       | 2     | 59       |
| 2       | 1     | 11       |
| 1       | 3     | 20       |
| 3       | 4     | 100      |
| 3       | 4     | 200      |
| 3       | 4     | 200      |
| 4       | 3     | 499      |
+---------+-------+----------+
输出:
+---------+---------+------------+----------------+
| person1 | person2 | call_count | total_duration |
+---------+---------+------------+----------------+
| 1       | 2       | 2          | 70             |
| 1       | 3       | 1          | 20             |
| 3       | 4       | 4          | 999            |
+---------+---------+------------+----------------+
解释:
用户 1 和 2 打过 2 次电话,总时长为 70 (59 + 11)。
用户 1 和 3 打过 1 次电话,总时长为 20。
用户 3 和 4 打过 4 次电话,总时长为 999 (100 + 200 + 200 + 499)。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-calls-between-two-persons
//测试数据
Create table If Not Exists Calls (from_id int, to_id int, duration int);

insert into Calls (from_id, to_id, duration) values ('1', '2', '59');
insert into Calls (from_id, to_id, duration) values ('2', '1', '11');
insert into Calls (from_id, to_id, duration) values ('1', '3', '20');
insert into Calls (from_id, to_id, duration) values ('3', '4', '100');
insert into Calls (from_id, to_id, duration) values ('3', '4', '200');
insert into Calls (from_id, to_id, duration) values ('3', '4', '200');
insert into Calls (from_id, to_id, duration) values ('4', '3', '499');

解题思路

Calls表中保存了每一笔通话信息。包括拨出方、接收方、通话时长。
题目要求:统计每两个用户之间的通话记录汇总。因为A与B和B与A的通话记录统计结果是相同的,因此,题目要求返回的结果中,只返回一种组合即可(即:用户ID较小的放在左边,较大的放在右边)。
也就是说,一条通话记录只会被记录一次。
Calls表通话记录中,拨出方的用户ID有可能较小,接收方的用户ID也有可能较小。那么,我们可以先对通话记录进行标准化:把拨出方和接收方中用户ID较小的那一个放在第一字段,较大的那一个放在第二个字段。这就与题目要求的返回结果相同了,然后再直接使用GROUP BY+COUNT+SUM汇总即可。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
select
    person1,
    person2,
    count(1) call_count,
    sum(duration) total_duration
from (
    select
        case when from_id < to_id then from_id else to_id end person1,
        case when from_id < to_id then to_id else from_id end person2,
        duration
    from Calls
)a
group by person1,
    person2;
picture loss