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

map分组后取前10个_SQL分组查询后取每组的前N条记录

5951b6edf61d786852a5be04c1e0643e.png

一、前言

分组查询是常见的SQL查询语句。首先,我们知道MySQL数据库分组功能主要是通过GROUP BY关键字来实现的,而且GROUP BY通常得配合聚合函数来使用用,比如说分组之后你可以计数(COUNT),求和(SUM),求平均数(AVG)等。但是今天我们要探讨的不是GROUP BY关键字学习和使用,而是一种有点另类的“分组”查询。

最近,项目上遇到这样一个功能需求。系统中存在资讯信息这样一个功能模块,用于发布一些和业务相关的活动动态,其中每条资讯信息都有一个所属类型(如科技类的资讯、娱乐类、军事类···)和浏览量字段。

而业务系统的官网上需要滚动展示一些热门资讯信息列表(浏览量越大代表越热门),而且每个类别的相关资讯记录至多显示3条,换句话:“按照资讯分类分组,取每组的前3条资讯信息列表”。

后面在尝试 GROUP BY 使用的各种方式都不能实现,最后在查阅相关资料后找到了实现的解决方法。

下面,我将模拟一些实际的测试数据重现问题的解决过程。

一、数据准备

数据库: MySQL 8.0社区版

表设计

5ff8a5848eb5b0465f10f367f41b8813.png

初始化SQL语句:

07c5e384c2ae233b8d8922ff10f513c1.png

资讯分类示例数据如下:

3fe3438cbf0e42a602e263b59c8da1dd.png

资讯分类

资讯信息记录表示例数据如下:

1f8aaae92b0f7c7d4d5e478957996230.png

资讯信息记录表

需求 :取热门的资讯信息列表且每个类别只取前3条。

二、核心思想

一般意义上我们在取前N条记录时候,都是根据某个业务字段进行降序排序,然后取前N条就能实现。

形如“select * from info order by views asc limit 0,3 ”,这条SQL就是取info表中的前3条记录。

但是当你仔细阅读我们的题目要求,你会发现:“它是让你每个类型下都要取浏览量的前3条记录”

一种比较简单但是粗暴的方式就是在Java代码中循环所有的资讯类型,取出每个类型的前3条记录,最后进行汇总。虽然这种方式也能实现我们的要求,但存在很严重的弊端,有可能会发送多次(夸张的说成百上千次也是有可能)sql语句,这种程序显然是有重大缺陷的。

但是,我们换一种思路。我们想在查询每条资讯记录时要是能查出其所在类型的排名就好了,然后根据排名字段进行过滤就好了。这时候我们就想到了子查询,而且MySQL是可以实现这样的功能子查询的。要计算出某条资讯信息的在同资讯分类下所有记录中排第几名,换成算出 有多少条浏览量比当前记录的浏览量高,然后根据具体的多少(N)条+1就是N+1就是当前记录所在其分类下的的排名。

假如以本文上面的示例数据说明:就是在计算每个资讯信息记录时,多计算出一列作为其“排名”字段,然后取“排名”字段的小于等于3的记录即可。如果这里还不是很理解的话,就先看下面的SQL,然后根据SQL再回过头来理解这段话。

三、SQL实现

方法一

SQL语句:

723c3cf8135a465ccd6e4cfd76ed34ab.png

查询结果:

ca8f39446e2ef0d6cc8fdbbbff03947d.png

查询结果

说明:

分析top字段的子查询,发现其满足条件有两个:其一是info_type_id和当前记录的type_id相等;其二是info表所有记录大于

当前记录的浏览量且info_type_id相等的记录数量(假设为N),所有N+1就等于当前记录在其分类下的按照浏览量降序排名。

方法二

SQL语句:

657834cb50cbad1e712fa86f921d4f00.png

查询结果

8f199cefc1d3eb932b61f78cc5880eb3.png

说明: 方法二可以看做是方法一的变体。

方法三

SQL语句

SELECT t1.* FROMinfo t1where exists (SELECT count(*) + 1 FROM info t2 WHERE t2.info_type_id = t1.info_type_id AND t2.views > t1.views having (count(*) + 1) <= 3) ORDER BY t1.info_type_id

查询结果:

ee94a35284aae4345a027fa4e1ea0182.png

四、小结

其实,有时候在面临业务难题的时候,困难的地方往往不在技术本身,而在于我们解决问题的思维方式。

就正如案例中求记录的所在分类的排名,把其对等的“转换成有多少条同类别的记录的浏览量比当前记录的大(count聚合函数)”

问题马上就迎刃而解了。

原文来自微信公众号:程序亦非猿

相关文章:

  • 烧结多孔砖孔洞率_烧结砖各种缺陷消除方法
  • 华为云计算面试需要掌握的知识_一文快速掌握华为云IPv6基础知识及使用指南...
  • awr报告分析 mysql_爱数AnyRobot:一文详解Oracle运维分析实践
  • 如何分析案件的性质_对涉黑犯罪案件,刑事律师如何阅卷?
  • scara工业机器人外观_scara工业机器人有哪些知名的品牌?
  • 二项分布最值推导_杨志明:高考数列中的最值与范围问题
  • css文字中间加竖线_前端初学者李不白,html+css的角度,带你分析蘑菇街官网!!!...
  • 笔记本电脑频繁自动重启_电脑一直自动重启,教您电脑一直自动重启怎么解决...
  • 动词ing形式的5种用法_动词ing形式的5种用法
  • python tcp处理_Python-对Pcap文件进行处理,获取指定TCP流
  • tomcat人数限制_Tomcat修改最大连接数
  • bcb image 动态大小_制作Excel动态图表,只需要3个步骤,上班人士必备技能
  • 三星笔记文件存储路径_三星Note20发布会:硬件堆料很硬核,屏幕进一步升级
  • mysql 存储过程 c_MySQL 存储过程
  • mysql table exists_mysql8 参考手册-table_exists()过程
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • ES6系统学习----从Apollo Client看解构赋值
  • Vue学习第二天
  • 第十八天-企业应用架构模式-基本模式
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 一道闭包题引发的思考
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #### go map 底层结构 ####
  • #define、const、typedef的差别
  • #pragma pack(1)
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (04)odoo视图操作
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (2022 CVPR) Unbiased Teacher v2
  • (C++17) optional的使用
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (八)Spring源码解析:Spring MVC
  • (待修改)PyG安装步骤
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (篇九)MySQL常用内置函数
  • (转)ObjectiveC 深浅拷贝学习
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • . Flume面试题
  • .gitignore
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .net framework 4.0中如何 输出 form 的name属性。
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET 反射 Reflect
  • .Net 应用中使用dot trace进行性能诊断
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET开发者必备的11款免费工具
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET中使用Redis (二)