当前位置: 首页 > news >正文

【MySQL】日期格式为 YYYY-MM 无法直接使用 DATE_SUB 函数的解决方案(特殊处理 或 PERIOD_DIFF 函数)

力扣题

1、题目地址

1843. 可疑银行账户

2、模拟表

表:Accounts

Column NameType
account_idint
max_incomeint
  • account_id 是这张表具有唯一值的列。
  • 每行包含一个银行账户每月最大收入的信息。

表:Transactions

Column NameType
transaction_idint
account_idint
typeENUM
amountint
daydatetime
  • transaction_id 是这张表具有唯一值的列。
  • 每行包含一条转账信息。
  • type 是枚举类型(包含’Creditor’,‘Debtor’),其中 ‘Creditor’ 表示用户向其账户存入资金,‘Debtor’ 表示用户从其账户取出资金。
  • amount 是交易过程中的存入/取出的金额。

3、要求

如果一个账户在 连续两个及以上 月份的 总收入 超过最大收入(max_income),那么认为这个账户 可疑。 账户当月 总收入 是当月存入资金总数(即 transactions 表中 type 字段的 ‘Creditor’)。

编写一个解决方案,报告所有的 可疑 账户。

以 任意顺序 返回结果表

返回结果格式如下示例所示。

示例 1:

输入:
Accounts 表:

account_idmax_income
321000
410400

Transactions 表:

transaction_idaccount_idtypeamountday
23Creditor1071002021-06-02 11:38:14
44Creditor104002021-06-20 12:39:18
114Debtor588002021-07-23 12:41:55
14Creditor493002021-05-03 16:11:04
153Debtor755002021-05-23 14:40:20
103Creditor1021002021-06-15 10:37:16
144Creditor563002021-07-21 12:12:25
194Debtor1011002021-05-09 15:21:49
83Creditor649002021-07-26 15:09:56
73Creditor909002021-06-14 11:23:07

输出:

account_id
3

解释:

对于账户 3:

  • 在 2021年6月,用户收入为 107100 + 102100 + 90900 = 300100。
  • 在 2021年7月,用户收入为 64900。

可见收入连续两月超过21000的最大收入,因此账户3列入结果表中。

对于账户 4:

  • 在 2021年5月,用户收入为 49300。
  • 在 2021年6月,用户收入为 10400。
  • 在 2021年7月,用户收入为 56300。

可见收入在5月与7月超过了最大收入,但6月没有。因为账户没有没有连续两月超过最大收入,账户4不列入结果表中。

4、代码编写

思路

1、Transactions 中根据 account_id 和 day里面的年月进行分组,加上查询条件 type=‘Creditor’(存入的钱),就可以查询到不同账户在不同月份存钱的总量

SELECT account_id, DATE_FORMAT(day, '%Y-%m') AS `month`, SUM(amount) AS sAmount
FROM Transactions
WHERE `type` = 'Creditor'
GROUP BY account_id, `month`
| account_id | month   | sAmount |
| ---------- | ------- | ------- |
| 3          | 2021-06 | 300100  |
| 4          | 2021-06 | 10400   |
| 4          | 2021-05 | 49300   |
| 4          | 2021-07 | 56300   |
| 3          | 2021-07 | 64900   |

2、要求里面是要连续两个月或以上总收入超过最大收入,那我们按最少两个月就行,将上面查询出来的连接自己,account_id 相同,月份(month)差距是一个月,满足总收入(sAmount)超过最大收入(max_income)就行

第一版写法(日期 YYYY-MM 格式特殊处理)

WITH tmp AS(SELECT account_id, DATE_FORMAT(day, '%Y-%m') AS `month`, SUM(amount) AS sAmountFROM TransactionsWHERE `type` = 'Creditor'GROUP BY account_id, `month`
)
SELECT DISTINCT one.account_id
FROM tmp AS one, tmp AS two
WHERE one.account_id = two.account_id
AND CONCAT(one.month, '01') = DATE_SUB(CONCAT(two.month, '-01'), INTERVAL 1 MONTH)
AND one.sAmount > (SELECT max_income FROM Accounts WHERE account_id = one.account_id)
AND two.sAmount > (SELECT max_income FROM Accounts WHERE account_id = two.account_id)

说一下我为什么这样用:
首先我测试 select date_sub('2023-02', interval 1 month),期望结果是 2023-01,但是结果是 Null
其次我再测试 select date_sub('2023-02-01', interval 1 month),这次正常输出,结果是 2023-01-01
所以就有了个想法,拼接后面的 -01,使用 concat 函数进行拼接即可,即 select date_sub(concat('2023-02','-01'), interval 1 month)

第二版写法(日期格式用 YYYYMM 使用 PERIOD_DIFF 函数)

PERIOD_DIFF
1、PERIOD_DIFF() 函数返回两日期之间的差异,结果以月份计算。
2、period1 和 period2 应采用相同的格式(格式为YYMM或YYYYMM)
3、语法:PERIOD_DIFF(period1, period2)

测试:
select period_diff('202302', '202301'),结果 1
select period_diff('2302', '2301'),结果 1
select period_diff('202301', '202302'),结果 -1
select period_diff('2301', '2302'),结果 -1

参考:MySQL PERIOD_DIFF() 函数

WITH tmp AS(SELECT account_id, DATE_FORMAT(day, '%Y%m') AS `month`, SUM(amount) AS sAmountFROM TransactionsWHERE `type` = 'Creditor'GROUP BY account_id, `month`
)
SELECT DISTINCT one.account_id
FROM tmp AS one, tmp AS two
WHERE one.account_id = two.account_id
AND PERIOD_DIFF(two.month, one.month) = 1
AND one.sAmount > (SELECT max_income FROM Accounts WHERE account_id = one.account_id)
AND two.sAmount > (SELECT max_income FROM Accounts WHERE account_id = two.account_id)

注意:日期转换 %Y 和 %m 对应 YYYY 和 MM(mm是分钟,MM才是月份,注意不要弄错)

date_format( ) 转换格式:

格式描述
%M月名
%m月,数值(00-12)
%Y年,4 位
%y年,2 位
http://www.lryc.cn/news/278708.html

相关文章:

  • Redis的key淘汰方式和内存不足淘汰方式
  • java使用redis
  • MySQL技能树
  • redis获取过期时间
  • ERROR in Plugin “react“ was conflicted .... 天坑留念-turborepo、eslint plugin
  • MergeTwoSortedLists 【合并有序链表】
  • 基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpRequest模块 解析http请求协议
  • muduo网络库剖析——网络地址InetAddress类
  • 什么是本地IP?服务器本地IP有哪些优势?
  • Open CASCADE学习|参数化球面的奇异性
  • 基础知识篇(一)Acticity生命周期
  • Java内存结构
  • Java--ListUtil工具类,实现将一个大列表,拆分成指定长度的子列表
  • SpringSecurity 密码加密登录
  • 大模型实战作业03
  • 【AI视野·今日Sound 声学论文速览 第四十四期】Tue, 9 Jan 2024
  • Windows Copilot 更新及使用教程
  • 【Android开发】不同Activity之间的数据回传实例(一)摘桃子游戏
  • 增量式PID和脉冲轴组合控制阀门开度(算法介绍)
  • 解决Vue.js Devtools未检测到Vue实例的问题
  • 【Java基础】进程与线程,并发与并行,CPU单核与多核
  • git修改最新提交(commit)信息
  • 想寻找Axure的替代品?我们已经试用了10+款设计工具,来看看吧!
  • 报文大小限制、请求体类型总结
  • rknn加载onnx时报错 GLIBC=2.29 no found librknnc.so
  • ASP .net core微服务实战(杨中科)
  • 使用命令行方式搭建uni-app + Vue3 + Typescript + Pinia + Vite + Tailwind CSS + uv-ui开发脚手架
  • VUE+bpmn.js实现工作流
  • 微信小程序Burp抓包
  • 基础篇_面向对象(什么是对象,对象演化,继承,多态,封装,接口,Service,核心类库,异常处理)