[MySQL] 分组排序取前N条记录以及生成自动数字序列,类似group by后 limit

简介: 前言:        同事的业务场景是,按照cid、author分组,再按照id倒叙,取出前2条记录出来。
前言:

        同事的业务场景是,按照cid、author分组,再按照id倒叙,取出前2条记录出来。

        oracle里面可以通过row_number() OVER (PARTITION BY cid,author ORDER BY id DESC) 表示根据cid,author分组,在分组内部根据id排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的),而mysql数据库就没有这样的统计函数,需要自己写复杂的sql来实现。


1,录入测试数据

  1. USE csdn;
  2. DROP TABLE IF EXISTS test;
  3. CREATE TABLE test (
  4.   id INT PRIMARY KEY,
  5.   cid INT,
  6.   author VARCHAR(30)
  7. ) ENGINE=INNODB;


  8. INSERT INTO test VALUES 
  9. (1,1,\'test1\'),
  10. (2,1,\'test1\'),
  11. (3,1,\'test2\'),
  12. (4,1,\'test2\'),
  13. (5,1,\'test2\'),
  14. (6,1,\'test3\'),
  15. (7,1,\'test3\'),
  16. (8,1,\'test3\'),
  17. (9,1,\'test3\'),
  18. (10,2,\'test11\'),
  19. (11,2,\'test11\'),
  20. (12,2,\'test22\'),
  21. (13,2,\'test22\'),
  22. (14,2,\'test22\'),
  23. (15,2,\'test33\'),
  24. (16,2,\'test33\'),
  25. (17,2,\'test33\'),
  26. (18,2,\'test33\');
  27. INSERT INTO test VALUES (200,200,\'200test_nagios\');

2,原始的效率比较低下的子查询实现方式
SQL代码如下:


  1. SELECT * FROM test a 
  2. WHERE 
  3. N>(
  4.     SELECT COUNT(*) 
  5.     FROM test b
  6.     WHERE a.cid=b.cid AND a.`author`=b.`author` AND a.id<b.id
  7. )ORDER BY cid,author,id DESC;

只要将N换成你要的数字比如2,就表示查询出每个分组的前2条记录,如下所示:

  1. mysql> SELECT * FROM test a 
  2.     -> WHERE 
  3.     -> 2>(
  4.     -> SELECT COUNT(*) 
  5.     -> FROM test b
  6.     -> WHERE a.cid=b.cid AND a.`author`=b.`author` AND a.id<b.id
  7.     -> )ORDER BY cid,author,id DESC;
  8. +-----+------+----------------+
  9. | id | cid | author |
  10. +-----+------+----------------+
  11. | 2 | 1 | test1 |
  12. | 1 | 1 | test1 |
  13. | 5 | 1 | test2 |
  14. | 4 | 1 | test2 |
  15. | 9 | 1 | test3 |
  16. | 8 | 1 | test3 |
  17. | 11 | 2 | test11 |
  18. | 10 | 2 | test11 |
  19. | 14 | 2 | test22 |
  20. | 13 | 2 | test22 |
  21. | 18 | 2 | test33 |
  22. | 17 | 2 | test33 |
  23. | 200 | 200 | 200test_nagios |
  24. +-----+------+----------------+
  25. 13 ROWS IN SET (0.00 sec)


  26. mysql>


3,使用动态sql来实现
先构造序列号码,引入一个@row来做rownumber
SET @row=0;SET @mid='';SELECT cid, author, @row:=@row+1 rownum FROM test ORDER BY  cid, author LIMIT 10;   

序列号码已经出来了,再加一个@mid来进行分组,重点在于CASE WHEN @mid = author THEN @row:=@row+1 ELSE @row:=1 END rownum,表示分组的时候会自动从1计数指导这个分组数据遍历结束。
SET @row=0;SET @mid='';SELECT cid, author,CASE WHEN @mid = author THEN @row:=@row+1 ELSE @row:=1 END rownum, @mid:=author FROM test ORDER BY cid,author DESC LIMIT 20;  

好了,再外面加一层inner JOIN 再对 rownumber 做限制 就可以拿到目标数据了。
SET @row=0;
SET @mid='';
SELECT a.*,b.rownum FROM test a 
INNER JOIN (
SELECT cid, author, id, CASE WHEN @mid = author THEN @row:=@row+1 ELSE @row:=1 END rownum, @mid:=author MID 
FROM test 
ORDER BY cid,author,id DESC
) b ON b.author=a.author AND b.cid=a.cid AND b.id=a.id  WHERE b.rownum<3;  


执行结果如下所示:

  1. mysql> SET @row=0;
  2. QUERY OK, 0 ROWS affected (0.00 sec)


  3. mysql> SET @mid=\'\';
  4. QUERY OK, 0 ROWS affected (0.00 sec)


  5. mysql> SELECT a.*,b.rownum FROM test a 
  6.     -> INNER JOIN (
  7.     -> SELECT cid, author, id, CASE WHEN @mid = author THEN @row:=@row+ELSE @row:=END rownum, @mid:=author MID 
  8.     -> FROM test 
  9.     -> ORDER BY cid,author,id DESC
  10.     -> ) b ON b.author=a.author AND b.cid=a.cid AND b.id=a.id WHERE b.rownum<3; 
  11. +-----+------+----------------+--------+
  12. | id | cid | author | rownum |
  13. +-----+------+----------------+--------+
  14. | 2 | 1 | test1 | 1 |
  15. | 1 | 1 | test1 | 2 |
  16. | 5 | 1 | test2 | 1 |
  17. | 4 | 1 | test2 | 2 |
  18. | 9 | 1 | test3 | 1 |
  19. | 8 | 1 | test3 | 2 |
  20. | 11 | 2 | test11 | 1 |
  21. | 10 | 2 | test11 | 2 |
  22. | 14 | 2 | test22 | 1 |
  23. | 13 | 2 | test22 | 2 |
  24. | 18 | 2 | test33 | 1 |
  25. | 17 | 2 | test33 | 2 |
  26. | 200 | 200 | 200test_nagios | 1 |
  27. +-----+------+----------------+--------+
  28. 13 ROWS IN SET (0.01 sec)


  29. mysql>
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
SQL 关系型数据库 MySQL
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
|
存储 关系型数据库 MySQL
MySQL中实施排序(sorting)及分组(grouping)操作的技巧。
使用这些技巧时,需要根据实际的数据量、表的设计和服务器性能等因素来确定最合适的做法。通过反复测试和优化,可以得到最佳的查询性能。
501 0
|
SQL Oracle 关系型数据库
【YashanDB知识库】如何将mysql含有group by的SQL转换成崖山支持的SQL
本文探讨了在YashanDB(崖山数据库)中执行某些SQL语句时出现的报错问题,对比了MySQL的成功执行结果。问题源于SQL-92标准对非聚合列的严格限制,要求这些列必须出现在GROUP BY子句中,而SQL:1999及更高版本允许非聚合列直接出现在选择列中。YashanDB和Oracle遵循SQL-92标准,因此会报错。文章提供了两种解决方法:使用聚合函数处理非聚合列,或将GROUP BY与ORDER BY拆分为两层查询。最后总结指出,SQL-92标准更为严谨合理,建议开发者遵循此规范以避免潜在问题。
|
SQL Oracle 关系型数据库
【YashanDB 知识库】如何将 mysql 含有 group by 的 SQL 转换成崖山支持的 SQL
在崖山数据库中执行某些 SQL 语句时出现报错(YAS-04316 not a single-group group function),而这些语句在 MySQL 中能成功执行。原因是崖山遵循 SQL-92 标准,不允许选择列表中包含未在 GROUP BY 子句中指定的非聚合列,而 MySQL 默认允许这种操作。解决办法包括:使用聚合函数处理非聚合列或拆分查询为两层,先进行 GROUP BY 再排序。总结来说,SQL-92 更严格,确保数据一致性,MySQL 在 5.7 及以上版本也默认遵循此标准。
|
SQL 缓存 关系型数据库
MySQL Limit实现原理
本文深入解析了MySQL中`LIMIT`子句的实现原理及其在分页、性能优化等场景下的应用技巧。文章详细介绍了`LIMIT`的基本语法、MySQL内部处理流程,以及如何通过索引优化、覆盖索引等策略提升分页查询的性能,并提供了实践建议。
1228 3
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
关系型数据库 MySQL PostgreSQL
postgresql和mysql中的limit使用方法
postgresql和mysql中的limit使用方法
843 1
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
本文详细解析了MySQL中`ORDER BY`的实现原理及优化方法。通过解析与优化、执行及多种优化技术,如索引利用、内存排序、外部排序等,帮助你提升排序性能。了解其背后的机制,可显著优化查询效率。
1009 4
|
SQL 缓存 关系型数据库
MySQL Limit实现原理
本文详细探讨了MySQL中`LIMIT`子句的实现原理及其在不同场景下的应用。`LIMIT`用于控制查询结果的行数,结合`OFFSET`可实现分页查询。其内部实现涉及解析器、优化器和执行器三部分,通过索引利用、子查询优化等提升性能。文章还提供了性能优化策略,如索引优化、覆盖索引及延迟关联等,并给出实践建议。
611 4
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
在实际开发中,我们经常会使用 MySQL 的 `ORDER BY`进行排序,那么,`ORDER BY`是如何实现的排序的?我们该如何优化 `ORDER BY`的排序性能?这篇文章,我们来聊一聊。
290 4

推荐镜像

更多