【daily】sql分组,每组取N条
数据准备
-- mysql语法
DROP TABLE IF EXISTS `test_group_type`;
CREATE TABLE `test_group_type` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` int(255) NOT NULL COMMENT '分类',
`sortno` int(11) NOT NULL DEFAULT '1' COMMENT '分类排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
INSERT INTO `test_group_type` VALUES ('1', '1', '1');
INSERT INTO `test_group_type` VALUES ('2', '2', '1');
INSERT INTO `test_group_type` VALUES ('3', '2', '2');
INSERT INTO `test_group_type` VALUES ('4', '3', '1');
INSERT INTO `test_group_type` VALUES ('5', '3', '2');
INSERT INTO `test_group_type` VALUES ('6', '3', '3');
INSERT INTO `test_group_type` VALUES ('7', '4', '4');
INSERT INTO `test_group_type` VALUES ('8', '4', '3');
INSERT INTO `test_group_type` VALUES ('9', '4', '1');
INSERT INTO `test_group_type` VALUES ('10', '4', '2');
需求说明
取每个分类的前3条数据。
实现
SELECT * from test_group_type p
where (select count(1) from test_group_type r where r.type = p.type and r.id < p.id) < 3
ORDER BY p.type, p.id
r.id < p.id 或 r.id > p.id, 区别是: 取前, 还是取后。
r.id < p.id结果:

r.id > p.id结果:

sql解释:
核心是select count(1) from test_group_type r where r.type = p.type and r.id < p.id。
首先, 理解select count(1) from test_group_type r where r.type = p.type, 统计与当前行类型相同的一共有多少行。
然后r.id < p.id, 只统计当前行之前的数据(因为表结构的id是自增)。
比如id=7, 实际就是 select count(1) from test_group_type r where r.type = 4 and r.id < 7, 结果是0, 并且0 < 3, true。
所以id=7的行被选中。
类推,id=10, 结果是3 < 3, false, 所以不满足。
扩展
以上是建立在id有序自增长的基础上,如果想要自定义排序要怎么写?
如果理解了前面的sql, 那么只需要改变count的筛选。
比如,取type=4根据sortno排序的前3条。
SELECT * from test_group_type p
where p.type = 4
and (select count(1) from test_group_type r where r.type = p.type and r.sortno < p.sortno) < 3
ORDER BY p.type, p.id
结果:
r.sortno < p.sortno:
r.sortno > p.sortno: 
方式二 (2017-11-28): mysql动态sql实现 特别: 并未测试大量数据下的性能, 但感觉效率不高
上面方式如果是根据sortno排序有bug. 比如数据结构如下:

取每组前4条,排序规则order by sortno, id. 理想结果是(type=4): 11, 3, 7, 8
如果用方式一得到的结果: (因为sortno存在相同, 且sortno不足4条)

于是另外一种方式是: 利用动态sql先对每行数据进行组内排序, 再取rownum <= 4
SELECT t1.*
, case when @type = t1.type then @row:=@row+1 else @row:=1 END rownum
, @type:=t1.type rowtype
from test_group_type t1
ORDER BY t1.type, t1.sortno, t1.id
结果:

sql解释:
1、首先要明确sql执行顺序select * from的*是最后执行的;
2、所以以上sql在order by后, 再追加组内排序号rownum。
@type是变量, @type:=t1.type即把每行的type赋值给变量。
当@type不等于当前行type时(即改行是该type的第一行),所以rownum=1;
当@type等于当前行type时,rownum递增;
-- 完整sql
SELECT tt.id, tt.type, tt.sortno from(
SELECT t1.*
, case when @type = t1.type then @row:=@row+1 else @row:=1 END rownum
, @type:=t1.type rowtype
from test_group_type t1
ORDER BY t1.type, t1.sortno, t1.id
) tt where tt.rownum <= 4;

【daily】sql分组,每组取N条的更多相关文章
- SQL分组排序后取每组最新一条数据的另一种思路
在hibernate框架和mysql.oracle两种数据库兼容的项目中实现查询每个id最新更新的一条数据. 之前工作中一直用的mybatis+oracle数据库这种,一般写这类分组排序取每组最新一条 ...
- SQL语句:随机取3条不重复的记录
随机取3条不重复的记录 [Access]select top 3 * from tablename order by rnd(id); [SqlServer]select top 3 * from t ...
- sql 分组后 组内排名
语法:ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN) 简单的说row_number()从1开始,为每一条分组记录返回一个数字,这里的ROW ...
- sql语句实现随机取n条数据(转)
我想把数组打乱随机取些值,于是用PHP的shuffl()打乱数组,当然,array_rand()也是可以随机取数组的,但是我想到另一个更高效的办法,是不是能用sql直接随机数据?当然可以! mysql ...
- SQL 查询每组的第一条记录
CREATE TABLE [dbo].[test1]( [program_id] [int] NULL, [person_id] [int] NULL ) ON [PRIMARY] /*查询每组分组中 ...
- sql重复数据只取一条记录
1.SQL SELECT DISTINCT 语句 在表中,可能会包含重复值.这并不成问题,不过,仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值. 语法: SEL ...
- SQL 分组获取产品 前两条记录
select * from ( select *, ROW_NUMBER() over(partition by IPAddress order by recordtime desc) as rowN ...
- sql 分组取每组的前n条或每组的n%(百分之n)的数据
sql 分组取每组的前n条或每组的n%(百分之n)的数据 sql keyword: SELECT * ,ROW_NUMBER() OVER(partition by b.UserID order by ...
- 记一次有意思的 SQL 实现 → 分组后取每组的第一条记录
开心一刻 今天,朋友气冲冲的走到我面前 朋友:我不是谈了个女朋友,谈了三个月嘛,昨天我偷看她手机,你猜她给我备注什么 我:备注什么? 朋友:舔狗 2 号! 我一听,气就上来了,说道:走,找她去,这婆娘 ...
随机推荐
- 理解Javascript的柯里化
前言 本文1454字,阅读大约需要4分钟. 总括: 本文以初学者的角度来阐述Javascript中柯里化的概念以及如何在工作中进行使用. 原文地址:理解Javascript的柯里化 知乎专栏: 前端进 ...
- Day6-Python3基础-面向对象编程
面向过程 VS 面向对象 编程范式 编程是 程序 员 用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大 ...
- Springboot | 私人订制你的banner
1. 搭建一个springboot模块 2. 配置POM文件 3. 自定义banner 3.1 自定义文字字符图案banner 3.2 自定义图案字符图案banner 自定义banner有什么用呢? ...
- Scala 学习(8)之「trait (2) 」
trait调用链 Scala 中支持让类继承多个 trait 后,依次调用多个 trait 中的同一个方法,只要让多个 trait 的同一个方法中,在最后都执行super.方法即可 类中调用多个 tr ...
- 为什么用nginx:它的5个主要优点
1.高并发,高性能 2.可扩展性好啊 3.高可靠性 4.热部署 5.BSD许可证
- Vmware初次安装虚拟机需要做的一些网络配置——nat模式与桥接模式
一.本机设置: 1.首先点击图中红线区域: 2.点击网络适配器 3.会出现如下区域: 4.网卡开启后设置ip地址,此处设置的ip和本机的ip没有关系,设置成你虚拟机里面运行的计算机需要的ip地址网段 ...
- 【Pycharm使用者必看】自定义【光标快速定位到行尾】的按键
1.问题描述 使用Pycharm写代码时,有很多比较方便的快捷键,比如:Shift+Enter快速切换到下一行, 但每次切换到多个括号外或者想移动到行尾,就必须按 End 键或者鼠标点击, 这样操作幅 ...
- 微信小程序开发技巧总结(二) -- 文件的选取、移动、上传和下载
微信小程序开发技巧总结(二) -- 文件的选取.移动.上传和下载 1.不同类型文件的选取 1.1 常用的图片 视频 对于大部分开发者来说,需要上传的文件形式主要为图片,微信为此提供了接口. wx.ch ...
- 一口气说出Redis 5种数据结构及对应使用场景,面试要加分的
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...
- Python应用——多变量的灵活处理
本文始发于个人公众号:TechFlow,原创不易,求个关注 我们都知道Python是一个非常灵活的语言,以至于如果它不是你的第一门语言,你会发现它总能给你各种各样的惊喜,让你忍不住惊叹:woc,还有这 ...