数据准备

-- 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条的更多相关文章

  1. SQL分组排序后取每组最新一条数据的另一种思路

    在hibernate框架和mysql.oracle两种数据库兼容的项目中实现查询每个id最新更新的一条数据. 之前工作中一直用的mybatis+oracle数据库这种,一般写这类分组排序取每组最新一条 ...

  2. SQL语句:随机取3条不重复的记录

    随机取3条不重复的记录 [Access]select top 3 * from tablename order by rnd(id); [SqlServer]select top 3 * from t ...

  3. sql 分组后 组内排名

    语法:ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN) 简单的说row_number()从1开始,为每一条分组记录返回一个数字,这里的ROW ...

  4. sql语句实现随机取n条数据(转)

    我想把数组打乱随机取些值,于是用PHP的shuffl()打乱数组,当然,array_rand()也是可以随机取数组的,但是我想到另一个更高效的办法,是不是能用sql直接随机数据?当然可以! mysql ...

  5. SQL 查询每组的第一条记录

    CREATE TABLE [dbo].[test1]( [program_id] [int] NULL, [person_id] [int] NULL ) ON [PRIMARY] /*查询每组分组中 ...

  6. sql重复数据只取一条记录

    1.SQL SELECT DISTINCT 语句 在表中,可能会包含重复值.这并不成问题,不过,仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值. 语法: SEL ...

  7. SQL 分组获取产品 前两条记录

    select * from ( select *, ROW_NUMBER() over(partition by IPAddress order by recordtime desc) as rowN ...

  8. sql 分组取每组的前n条或每组的n%(百分之n)的数据

    sql 分组取每组的前n条或每组的n%(百分之n)的数据 sql keyword: SELECT * ,ROW_NUMBER() OVER(partition by b.UserID order by ...

  9. 记一次有意思的 SQL 实现 → 分组后取每组的第一条记录

    开心一刻 今天,朋友气冲冲的走到我面前 朋友:我不是谈了个女朋友,谈了三个月嘛,昨天我偷看她手机,你猜她给我备注什么 我:备注什么? 朋友:舔狗 2 号! 我一听,气就上来了,说道:走,找她去,这婆娘 ...

随机推荐

  1. 每天一道Java题[8]

    以下题目及解答属于个人见解,欢迎大家也分享和补充一下解答的内容,互相促进,共同进步! 题目 RESTful WebService与SOAP WebService有什么异同? 解答 SOAP是一个协议, ...

  2. JWT | io.jsonwebtoken.security.WeakKeyException: The signing key's size is 1024 bits which is not se

    背景 今天集成JWT的时候,选用了PS256算法,在用使用PGP KEY作为私钥JWT进行签名的时候,报了如下错误: "C:\Program Files\Java\jdk1.8.0_161\ ...

  3. Shrio | java.io.IOException: Resource [classpath:shiro.ini] could not be found

    案例 今天项目启动时一直报异常,看了错误日志发现是shrio文件找不到引起的,异常: java.io.IOException: Resource [classpath:shiro.ini] could ...

  4. vue简介,插值表达式,过滤器

    目录 VUE框架介绍 what?什么是vue? why?为什么要学习vue? special特点? how如何使用? 下载安装? 导入方式? 挂在点el 插值表达式 delimiters自定义插值表达 ...

  5. idea个人配置记录

    idea.properties # Use ${idea.home.path} macro to specify location relative to IDE installation home. ...

  6. RestTemplate工具类根据服务名发送请求

    要使用RestTemplate 根据服务名发送请求的话需要 使用  @LoadBalanced  这个注解,用了这个注解的RestTemplate就不用使用  ip 来请求了,首先要创建一个配置类 i ...

  7. 小白学习VUE第二课:环境搭建 VUE Node.js VSCode template模板

    环境搭建 VUE Node.js VSCode template模板: 首先安装node:http://www.runoob.com/nodejs/nodejs-install-setup.html ...

  8. DG参数 LOG_ARCHIVE_DEST_n

    DG参数 LOG_ARCHIVE_DEST_n This chapter provides reference information for the attributes of the LOG_AR ...

  9. DRF框架的安装与使用

    目录 DRF框架的安装与配置 基于restful接口规范的接口设计 DRF框架的安装与配置 """ 1)安装 >: pip install djangorestfr ...

  10. 【题解】[P1045] 麦森数

    题目 题目描述 形如2^P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P-1 不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=30213 ...