力扣题
1、题目地址
2993. 发生在周五的交易 I
2、模拟表
表:Purchases
| Column Name | Type | 
|---|---|
| user_id | int | 
| purchase_date | date | 
| amount_spend | int | 
- (user_id, purchase_date, amount_spend) 是该表的主键(具有唯一值的列)。
- purchase_date 的范围从 2023 年 11 月 1 日到 2023 年 11 月 30 日,并包括这两个日期。
- 每一行包含 user id,purchase date 和 amount spend。
3、要求
- 编写一个解决方案,计算用户在 2023 年 11 月 的 每个星期五 的 总花费。
- 输出所有在 周五 有购买记录的周。
- 按照每月的周次序 升序 排列结果表。
4、示例
输入:
Purchases 表:
| user_id | purchase_date | amount_spend | 
|---|---|---|
| 11 | 2023-11-07 | 1126 | 
| 15 | 2023-11-30 | 7473 | 
| 17 | 2023-11-14 | 2414 | 
| 12 | 2023-11-24 | 9692 | 
| 8 | 2023-11-03 | 5117 | 
| 1 | 2023-11-16 | 5241 | 
| 10 | 2023-11-12 | 8266 | 
| 13 | 2023-11-24 | 12000 | 
输出:
| week_of_month | purchase_date | total_amount | 
|---|---|---|
| 1 | 2023-11-03 | 5117 | 
| 4 | 2023-11-24 | 21692 | 
解释:
- 在 2023 年 11 月的第一周,于 2023-11-03 星期五发生了总额为 $5,117 的交易。
- 对于 2023 年 11 月的第二周,于 2023-11-10 星期五没有交易。
- 同样,在 2023 年 11 月的第三周,于 2023-11-17 星期五没有交易。
- 在 2023 年 11 月的第四周,于 2023-11-24 星期五发生了两笔交易,分别为 $12,000 和 $9,692,总计为 $21,692。
- 输出表按照 week_of_month 升序排列。
5、代码编写
我的写法
SELECT CEILING((DAY(purchase_date)+WEEKDAY(purchase_date-INTERVAL DAY(purchase_date)-1 DAY)) / 7) AS week_of_month, purchase_date, SUM(amount_spend) AS total_amount
FROM Purchases
WHERE WEEKDAY(purchase_date) = 4
AND YEAR(purchase_date) = '2023'
AND MONTH(purchase_date) = '11'
GROUP BY week_of_month
ORDER BY week_of_month
代码分析
例子:purchase_date = ‘2023-11-03’
1、本月第几天,结果为 3
SELECT DAY(purchase_date);
2、本月第一天日期,结果为 2023-11-01
SELECT purchase_date - INTERVAL DAY(purchase_date)-1 DAY;
3、本月第一天是周几,结果为 2(周三),会发现 WEEKDAY(月份第一天) 的结果值刚好是补齐日期矩阵需要的天数
 
SELECT WEEKDAY(purchase_date - INTERVAL DAY(purchase_date)-1 DAY);
4、当前天数加上补齐日期矩阵需要的上月占用的天数(相当于是第一周补全),结果为 5
| 一 | 二 | 三 | 四 | 五 | 六 | 日 | 
|---|---|---|---|---|---|---|
| 3 | 4 | 5 | 6 | 7 | ||
| 8 | 9 | 10 | 11 | 12 | 13 | 14 | 
| 15 | 16 | 17 | 18 | 19 | 20 | 21 | 
| 22 | 23 | 24 | 25 | 26 | 27 | 28 | 
| 29 | 30 | 31 | 32 | 
SELECT DAY(purchase_date) + WEEKDAY(purchase_date - INTERVAL DAY(purchase_date)-1 DAY);
5、从上面图很清晰可以看出可以用7的倍数去区分哪一周,第一周除以每周的天数 7,并向上取整,最终结果为 1
SELECT CEIL((DAY(purchase_date) + WEEKDAY(purchase_date - INTERVAL DAY(purchase_date)-1 DAY)) / 7);
网友代码(WEEK函数mode参数选择,比较合理)
思路:计算日期(2023-11-03)周数减去当前日期第一天(2023-11-01)周数加一,就可以算出日期是当月第几周
SELECT WEEK(purchase_date, 1) - WEEK('2023-11-01', 1) + 1 AS week_of_month,purchase_date,SUM(amount_spend) AS total_amount
FROM Purchases
WHERE WEEKDAY(purchase_date) = 4
GROUP BY purchase_date
GROUP BY purchase_date
WEEK函数接受两个参数:
- date是要获取周数的日期。
- mode是一个可选参数,用于确定周数计算的逻辑。
 它允许您指定本周是从星期一还是星期日开始,返回周数应在 0 到 52 之间或 0 到 53 之间。
 mode参数在一些网站上写的很多都细节不够,不容易理解,可以看下面参考里面的
参考
MySQL 计算当前日期属于本月第几周
 MySQL week() 函数及参数 mode 详解