【力扣 | 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_idproduct_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
相关推荐
算AI5 小时前
人工智能+牙科:临床应用中的几个问题
人工智能·算法
hyshhhh7 小时前
【算法岗面试题】深度学习中如何防止过拟合?
网络·人工智能·深度学习·神经网络·算法·计算机视觉
杉之8 小时前
选择排序笔记
java·算法·排序算法
烂蜻蜓8 小时前
C 语言中的递归:概念、应用与实例解析
c语言·数据结构·算法
OYangxf8 小时前
图论----拓扑排序
算法·图论
我要昵称干什么8 小时前
基于S函数的simulink仿真
人工智能·算法
AndrewHZ9 小时前
【图像处理基石】什么是tone mapping?
图像处理·人工智能·算法·计算机视觉·hdr
念九_ysl9 小时前
基数排序算法解析与TypeScript实现
前端·算法·typescript·排序算法
守正出琦9 小时前
日期类的实现
数据结构·c++·算法
ChoSeitaku9 小时前
NO.63十六届蓝桥杯备战|基础算法-⼆分答案|木材加工|砍树|跳石头(C++)
c++·算法·蓝桥杯