题目描述

(通过次数4,801 | 提交次数10,828,通过率44.34%)

用户表:Users

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| user_id      | int     |
| user_name    | varchar |
| credit       | int     |
+--------------+---------+
user_id 是这个表的主键。
表中的每一列包含每一个用户当前的额度信息。

交易表:Transactions
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| trans_id      | int     |
| paid_by       | int     |
| paid_to       | int     |
| amount        | int     |
| transacted_on | date    |
+---------------+---------+
trans_id 是这个表的主键。
表中的每一列包含银行的交易信息。
ID 为 paid_by 的用户给 ID 为 paid_to 的用户转账。

力扣银行 (LCB) 帮助程序员们完成虚拟支付。我们的银行在表Transaction中记录每条交易信息,我们要查询每个用户的当前余额,并检查他们是否已透支(当前额度小于 0)。

写一条 SQL 语句,查询:
user_id用户 ID
user_name用户名
credit完成交易后的余额
credit_limit_breached检查是否透支 ("Yes" 或"No")
以任意顺序返回结果表。

查询格式见如下所示。
示例 1:
输入:
Users 表:
+------------+--------------+-------------+
| user_id    | user_name    | credit      |
+------------+--------------+-------------+
| 1          | Moustafa     | 100         |
| 2          | Jonathan     | 200         |
| 3          | Winston      | 10000       |
| 4          | Luis         | 800         | 
+------------+--------------+-------------+
Transactions 表:
+------------+------------+------------+----------+---------------+
| trans_id   | paid_by    | paid_to    | amount   | transacted_on |
+------------+------------+------------+----------+---------------+
| 1          | 1          | 3          | 400      | 2020-08-01    |
| 2          | 3          | 2          | 500      | 2020-08-02    |
| 3          | 2          | 1          | 200      | 2020-08-03    |
+------------+------------+------------+----------+---------------+
输出:
+------------+------------+------------+-----------------------+
| user_id    | user_name  | credit     | credit_limit_breached |
+------------+------------+------------+-----------------------+
| 1          | Moustafa   | -100       | Yes                   | 
| 2          | Jonathan   | 500        | No                    |
| 3          | Winston    | 9900       | No                    |
| 4          | Luis       | 800        | No                    |
+------------+------------+------------+-----------------------+
Moustafa 在 "2020-08-01" 支付了 $400 并在 "2020-08-03" 收到了 $200 ,当前额度 (100 -400 +200) = -$100
Jonathan 在 "2020-08-02" 收到了 $500 并在 "2020-08-08" 支付了 $200 ,当前额度 (200 +500 -200) = $500
Winston 在 "2020-08-01" 收到了 $400 并在 "2020-08-03" 支付了 $500 ,当前额度 (10000 +400 -500) = $9900
Luis 未收到任何转账信息,额度 = $800

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/bank-account-summary
//测试数据
Create table If Not Exists Users (user_id int, user_name varchar(20), credit int);
Create table If Not Exists Transactions (trans_id int, paid_by int, paid_to int, amount int, transacted_on date);

insert into Users (user_id, user_name, credit) values ('1', 'Moustafa', '100');
insert into Users (user_id, user_name, credit) values ('2', 'Jonathan', '200');
insert into Users (user_id, user_name, credit) values ('3', 'Winston', '10000');
insert into Users (user_id, user_name, credit) values ('4', 'Luis', '800');

insert into Transactions (trans_id, paid_by, paid_to, amount, transacted_on) values ('1', '1', '3', '400', '2020-08-01');
insert into Transactions (trans_id, paid_by, paid_to, amount, transacted_on) values ('2', '3', '2', '500', '2020-08-02');
insert into Transactions (trans_id, paid_by, paid_to, amount, transacted_on) values ('3', '2', '1', '200', '2020-08-03');

解题思路

Users表中保存了每个人的信用额度。
Transactions表中保存了每个人的每笔交易。
交易分收、支双方。对于收入方来说,相当于增加了信用额度。对于支出方来说,相当于消耗了信用额度。
题目要求:查询每个人的信用额度以及是否超支。
我们已经知道了每个人的原始信用额度,既然需要知道每个人是否超支,那么,就需要根据交易记录计算每个人的收支之和。
计算收支之和时,每条交易都是既要计算收入方,也要计算支出方。
方法一:

select
    user_id,
    sum(amount) amount
from (
    select
        paid_by user_id,
        amount amount
    from Transactions a
    union all
    select
        paid_to user_id,
        amount * -1 amount
    from Transactions a
)b
group by user_id;

方法二:

select
    a.user_id,
    max(a.credit) - 
      sum(case when a.user_id = b.paid_by then b.amount
            else coalesce(b.amount,0) * -1 end) credit
from Users a
left join Transactions b
on a.user_id = b.paid_by or a.user_id = b.paid_to
group by a.user_id;

知道了每个人的收支总和,与原始信用额度一对比,就可以很简单的判断出是否超支了。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。

select
    a.user_id,
    a.user_name,
    a.credit - coalesce(c.amount,0) credit,
    case when a.credit >= coalesce(c.amount,0) then 'No'
         else 'Yes' end credit_limit_breached
from Users a
left join (
    select
        user_id,
        sum(amount) amount
    from (
        select
            paid_by user_id,
            amount amount
        from Transactions a
        union all
        select
            paid_to user_id,
            amount * -1 amount
        from Transactions a
    )b
    group by user_id
)c
on a.user_id = c.user_id;
picture loss