当前位置:网站首页>MySQL分组后取最大一条数据【最优解】
MySQL分组后取最大一条数据【最优解】
2022-07-30 19:28:00 【繁华哟】
有一个简单而又常见的需求:分组后取每组的最大一条数据
一、表结构
xdx_user
CREATE TABLE `xdx_user` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`name` varchar(255) NOT NULL COMMENT '名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
xdx_notify
CREATE TABLE `xdx_notify` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`user_id` int(10) NOT NULL COMMENT '用户id',
`message` varchar(255) NOT NULL COMMENT '消息',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='通知表';
数据插入
INSERT INTO xdx_user (name) values ('张三'),('李四'),('王五');
INSERT into xdx_notify (user_id, message) VALUES
(1, '张三消息1'),(1, '张三消息2'),(1,'张三消息3'), (1, "张三消息 max"),
(2, '李四消息max'),
(3, '王五消息1'),( 3, '王五消息2'),( 3, '王五消息3'),(3, '王五消息4'),(3, '王五消息max');
二、SQL
要求查出每个用户的 id,姓名,最后一次接收的消息(也就是id最大的)
1 张三 张三消息 max
2 李四 李四消息max
3 王五 王五消息max
2-1、分组找出每个用户的消息最大值
SELECT
xu.id '用户ID',
xu.name '用户名',
xn.message '消息内容'
FROM xdx_user xu
LEFT JOIN (
SELECT * FROM xdx_notify
WHERE id IN (SELECT MAX(id) FROM xdx_notify GROUP BY user_id)
) xn ON xu.id = xn.user_id
2-2、先排序,再分组 (错误写法)
以前总以为这种办法是可以的,以为会按照分组之后取第一条,今天却发现不行,不知道是不是因为SQL版本的问题
SELECT
xu.id '用户ID',
xu.name '用户名',
xn.message '消息内容'
FROM xdx_user xu
LEFT JOIN (
SELECT *
FROM (SELECT * FROM xdx_notify ORDER BY id DESC)
tmp GROUP BY tmp.user_id
) xn ON xu.id = xn.user_id
2-3、关联子查询
SELECT
xu.id '用户ID',
xu.name '用户名',
xn.message '消息内容'
FROM xdx_user xu
LEFT JOIN (
SELECT * FROM xdx_notify a
WHERE id = (SELECT MAX(id) FROM xdx_notify b WHERE a.user_id = b.user_id)
) xn ON xu.id = xn.user_id
2-4、使用 NOT EXISTS
SELECT
xu.id '用户ID',
xu.name '用户名',
xn.message '消息内容'
FROM xdx_user xu
LEFT JOIN (
SELECT *
FROM xdx_notify a
WHERE NOT EXISTS (SELECT 1 FROM xdx_notify b WHERE a.user_id = b.user_id AND a.id < b.id)
) xn ON xu.id = xn.user_id
三、SQL分析
3-1、分组找出每个用户的消息最大值
通过执行结果发现,三次查询都没有走索引,都是全表扫描的
3-2、关联子查询
和上述结果一样,也是不走索引的
3-3、使用 NOT EXISTS
仔细看最里面的子查询,是走了主键索引的
3-4、总结
虽然上面的三种方法都可以拿到正确的结果,看似好像也差不多,但在实际的过程中却有很大的差别。
在主表900w数据,从表400w数据的时候,1、2写法几乎无法运行,但是写法3却可以很快的得出结果,最慢的就是最内层SQL执行比较慢,写法3却是走索引的所以要快很多。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
边栏推荐
- VBA 连接Access数据库和Excle
- JsonUtil基于字符串操作josn
- Alibaba Cloud Martial Arts Headline Event Sharing
- LeetCode 0952.按公因数计算最大组件大小:建图 / 并查集
- The advanced version of the Niu Ke brushing series (team competition, sorting subsequences, inverting strings, deleting common characters, repairing pastures)
- 解决终极bug,项目最终能顺利部署上线。
- 防抖和节流有什么区别,分别用于什么场景?
- MindSpore:【JupyterLab】按照新手教程训练时报错
- MindSpore:对image作normalize的目的是什么?
- 牛客刷题系列之进阶版(组队竞赛,排序子序列,倒置字符串, 删除公共字符,修理牧场)
猜你喜欢

【PyTorchVideo教程01】快速实现视频动作识别

2种手绘风格效果比较,你更喜欢哪一种呢?

谷歌AlphaFold近日宣称预测出地球上几乎所有蛋白质结构

redis

Does the satellite phone communicate directly with the satellite or through a ground station?

VBA runtime error '-2147217900 (80040e14): Automation error

【hbuilder】运行不了部分项目 , 打开终端 无法输入指令

VS Code connects to SQL Server

防抖和节流有什么区别,分别用于什么场景?

来了!东方甄选为龙江农产品直播带货
随机推荐
【PyTorchVideo教程01】快速实现视频动作识别
来了!东方甄选为龙江农产品直播带货
What is the value of biomedical papers? How to translate the papers into Chinese and English?
MySQL database - DQL data query language
- daily a LeetCode 】 【 191. A number of 1
电脑死机的时候,发生了什么?
C# wpf borderless window add shadow effect
VBA batch import Excel data into Access database
VBA connects Access database and Excel
iPhone真是十三香?两代产品完全对比,或许上一代更值得买
Listen to the boot broadcast
ImportError:attempted relative import with no known parent package
LeetCode每日一题(1717. Maximum Score From Removing Substrings)
7.30模拟赛总结
The use of @ symbol in MySql
055 c# print
Swiper轮播图片并播放背景音乐
尊重客观事实
Encapsulates a console file selector based on inquirer
Range.CopyFromRecordset 方法 (Excel)