【力扣 | SQL题 | 每日4题】力扣1596,1587,2228,2066

1. 力扣1596:每位顾客最经常订购的商品

1.1 题目:

表:Customers

复制代码
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| customer_id   | int     |
| name          | varchar |
+---------------+---------+
customer_id 是该表具有唯一值的列
该表包含所有顾客的信息

表:Orders

复制代码
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| order_id      | int     |
| order_date    | date    |
| customer_id   | int     |
| product_id    | int     |
+---------------+---------+
order_id 是该表具有唯一值的列
该表包含顾客 customer_id 的订单信息
没有顾客会在一天内订购相同的商品 多于一个

表:Products

复制代码
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| product_name  | varchar |
| price         | int     |
+---------------+---------+
product_id 是该表具有唯一值的列
该表包含了所有商品的信息

写一个解决方案,找到每一个顾客最经常订购的商品。

结果表单应该有每一位至少下过一次单的顾客 customer_id , 他最经常订购的商品的 product_id 和 product_name。

返回结果没有顺序要求。

查询结果格式如下例所示。

示例 1:

复制代码
输入:
Customers表:
+-------------+-------+
| customer_id | name  |
+-------------+-------+
| 1           | Alice |
| 2           | Bob   |
| 3           | Tom   |
| 4           | Jerry |
| 5           | John  |
+-------------+-------+
Orders表:
+----------+------------+-------------+------------+
| order_id | order_date | customer_id | product_id |
+----------+------------+-------------+------------+
| 1        | 2020-07-31 | 1           | 1          |
| 2        | 2020-07-30 | 2           | 2          |
| 3        | 2020-08-29 | 3           | 3          |
| 4        | 2020-07-29 | 4           | 1          |
| 5        | 2020-06-10 | 1           | 2          |
| 6        | 2020-08-01 | 2           | 1          |
| 7        | 2020-08-01 | 3           | 3          |
| 8        | 2020-08-03 | 1           | 2          |
| 9        | 2020-08-07 | 2           | 3          |
| 10       | 2020-07-15 | 1           | 2          |
+----------+------------+-------------+------------+
Products表:
+------------+--------------+-------+
| product_id | product_name | price |
+------------+--------------+-------+
| 1          | keyboard     | 120   |
| 2          | mouse        | 80    |
| 3          | screen       | 600   |
| 4          | hard disk    | 450   |
+------------+--------------+-------+
输出:
+-------------+------------+--------------+
| customer_id | product_id | product_name |
+-------------+------------+--------------+
| 1           | 2          | mouse        |
| 2           | 1          | keyboard     |
| 2           | 2          | mouse        |
| 2           | 3          | screen       |
| 3           | 3          | screen       |
| 4           | 1          | keyboard     |
+-------------+------------+--------------+
解释:
Alice (customer 1) 三次订购鼠标, 一次订购键盘, 所以鼠标是 Alice 最经常订购的商品.
Bob (customer 2) 一次订购键盘, 一次订购鼠标, 一次订购显示器, 所以这些都是 Bob 最经常订购的商品.
Tom (customer 3) 只两次订购显示器, 所以显示器是 Tom 最经常订购的商品.
Jerry (customer 4) 只一次订购键盘, 所以键盘是 Jerry 最经常订购的商品.
John (customer 5) 没有订购过商品, 所以我们并没有把 John 包含在结果表中.

1.2 思路:

最经常=>排名第一=>窗口函数

1.3 题解:

sql 复制代码
with tep1 as (
    select customer_id, t1.product_id, product_name 
    from Orders t1 
    join Products t2 
    on t1.product_id = t2.product_id
), tep2 as (
    select customer_id, product_id, product_name, count(*) cnt
    from tep1
    group by customer_id, product_id, product_name
), tep3 as (
    select customer_id, product_id, product_name,
    rank() over (partition by customer_id order by cnt desc) ranks
    from tep2
)

select customer_id, product_id, product_name
from tep3
where ranks = 1

2. 力扣1587:银行账户概要2

2.1 题目:

表: Users

复制代码
+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| account      | int     |
| name         | varchar |
+--------------+---------+
account 是该表的主键(具有唯一值的列)。
该表的每一行都包含银行中每个用户的帐号。
表中不会有两个用户具有相同的名称。

表: Transactions

复制代码
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| trans_id      | int     |
| account       | int     |
| amount        | int     |
| transacted_on | date    |
+---------------+---------+
trans_id 是该表主键(具有唯一值的列)。
该表的每一行包含了所有账户的交易改变情况。
如果用户收到了钱, 那么金额是正的; 如果用户转了钱, 那么金额是负的。
所有账户的起始余额为 0。

编写解决方案, 报告余额高于 10000 的所有用户的名字和余额. 账户的余额等于包含该账户的所有交易的总和。

返回结果表单 无顺序要求 。

查询结果格式如下例所示。

示例 1:

复制代码
输入:
Users table:
+------------+--------------+
| account    | name         |
+------------+--------------+
| 900001     | Alice        |
| 900002     | Bob          |
| 900003     | Charlie      |
+------------+--------------+

Transactions table:
+------------+------------+------------+---------------+
| trans_id   | account    | amount     | transacted_on |
+------------+------------+------------+---------------+
| 1          | 900001     | 7000       |  2020-08-01   |
| 2          | 900001     | 7000       |  2020-09-01   |
| 3          | 900001     | -3000      |  2020-09-02   |
| 4          | 900002     | 1000       |  2020-09-12   |
| 5          | 900003     | 6000       |  2020-08-07   |
| 6          | 900003     | 6000       |  2020-09-07   |
| 7          | 900003     | -4000      |  2020-09-11   |
+------------+------------+------------+---------------+
输出:
+------------+------------+
| name       | balance    |
+------------+------------+
| Alice      | 11000      |
+------------+------------+
解释:
Alice 的余额为(7000 + 7000 - 3000) = 11000.
Bob 的余额为1000.
Charlie 的余额为(6000 + 6000 - 4000) = 8000.

2.2 思路:

简单题。

2.3 题解:

sql 复制代码
select name, sum(amount) balance
from Users t1
join Transactions t2
on t1.account = t2.account
group by name
having sum(amount) > 10000

3. 力扣2228:7天内两次购买的用户

3.1 题目:

表: Purchases

复制代码
+---------------+------+
| Column Name   | Type |
+---------------+------+
| purchase_id   | int  |
| user_id       | int  |
| purchase_date | date |
+---------------+------+
purchase_id 包含唯一值。
该表包含用户从某个零售商购买的日期的日志。

编写解决方案,获取 最多 间隔 7 天进行两次购买的用户的 id。

返回按 user_id 排序的结果表。

结果格式如下所示。

示例 1:

复制代码
输入: 
Purchases 表:
+-------------+---------+---------------+
| purchase_id | user_id | purchase_date |
+-------------+---------+---------------+
| 4           | 2       | 2022-03-13    |
| 1           | 5       | 2022-02-11    |
| 3           | 7       | 2022-06-19    |
| 6           | 2       | 2022-03-20    |
| 5           | 7       | 2022-06-19    |
| 2           | 2       | 2022-06-08    |
+-------------+---------+---------------+
输出: 
+---------+
| user_id |
+---------+
| 2       |
| 7       |
+---------+
解释: 
用户 2 在 2022-03-13 和 2022-03-20 有两次购买。由于第二次购买是在第一次购买后的 7 天内,我们添加了他们的 ID。
用户 5 只购买了 1 次。
用户 7 在同一天有两次购买,所以我们添加了他们的 ID。

3.2 思路:

自连接就够了。

3.3 题解:

sql 复制代码
-- 一眼自连接:
-- 对于驱动表的一条数据,找出user_id相同,purchase_id不同
-- 且二者相差日期是小于等于7天的记录。
-- 即可满足题意。
select distinct t1.user_id 
from Purchases t1
join Purchases t2
on t1.user_id = t2.user_id and abs(datediff(t1.purchase_date, t2.purchase_date)) <= 7
and t1.purchase_id <> t2.purchase_id
order by user_id 

4. 力扣2066:账户余额

4.1 题目:

表名: Transactions

复制代码
+-------------+------+
| Column Name | Type |
+-------------+------+
| account_id  | int  |
| day         | date |
| type        | ENUM |
| amount      | int  |
+-------------+------+
(account_id, day) 是该Transactions表的主键.
表中的每行数据表示一次交易的信息, 包括此次交易的账号(account_id), 交易类型(type), 交易发生时间(day), 交易发生金额(amount).
其中交易类型(type)字段包括了两种行为:存入 ('Deposit'), 取出('Withdraw').

请写出能够返回用户每次交易完成后的账户余额. 我们约定所有用户在进行交易前的账户余额都为0, 并且保证所有交易行为后的余额不为负数。

返回的结果请依次按照 账户(account_id), 日期( day ) 进行升序排序 .

查询结果的格式请参照以下测试样例.

测试样例1:

复制代码
输入: 
Transactions 表:
+------------+------------+----------+--------+
| account_id | day        | type     | amount |
+------------+------------+----------+--------+
| 1          | 2021-11-07 | Deposit  | 2000   |
| 1          | 2021-11-09 | Withdraw | 1000   |
| 1          | 2021-11-11 | Deposit  | 3000   |
| 2          | 2021-12-07 | Deposit  | 7000   |
| 2          | 2021-12-12 | Withdraw | 7000   |
+------------+------------+----------+--------+
输出: 
+------------+------------+---------+
| account_id | day        | balance |
+------------+------------+---------+
| 1          | 2021-11-07 | 2000    |
| 1          | 2021-11-09 | 1000    |
| 1          | 2021-11-11 | 4000    |
| 2          | 2021-12-07 | 7000    |
| 2          | 2021-12-12 | 0       |
+------------+------------+---------+

解释: 
账户1:
- 初始金额为 0.
- 2021-11-07 --> 存入2000. 余额变为 0 + 2000 = 2000.
- 2021-11-09 --> 取出1000. 余额变为 2000 - 1000 = 1000.
- 2021-11-11 --> 存入3000. 余额变为 1000 + 3000 = 4000.
账户2:
- 初始金额为 0.
- 2021-12-07 --> 存入7000. 余额变为 0 + 7000 = 7000.
- 2021-12-12 --> 取出 7000. 余额变为 7000 - 7000 = 0.

4.2 思路:

窗口函数sum。

4.3 题解:

sql 复制代码
-- 一眼窗口函数,看balance字段的值变化即可=> sum

-- 第一步:先同步type,将type字段为Withdraw的amount记录变为负值
with tep as (
    select account_id , day, 
    case when type='Withdraw' then -amount
    else amount
    end amount
    from Transactions
)
-- 然后使用窗口函数,account_id分组,day排序,然后计算amount总和
select account_id, day, sum(amount) over (partition by account_id order by day) balance
from tep
相关推荐
UIU1147 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
论文复现现场8 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi8 小时前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
秋天的怀念_David9 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
碧海银沙音频科技研究院10 小时前
在PC电脑上用Whisper→Marian算法实现离线语音翻译功能
算法·whisper
niyongsheng10 小时前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
j7~13 小时前
【穷举、深搜与回溯算法】一棵决策树讲透全排列与子集
数据结构·c++·算法·leetcode·回溯·递归
傅科摆 _ py14 小时前
DP,贪心,堆和栈,二分力扣复习
开发语言·python·算法
Shaoshing14 小时前
LeetCode100 42.接雨水
java·算法·leetcode
域限奇点访客14 小时前
用AI生成问卷的网站怎么选?看题目录入结构、题型映射和生成后的校验
算法