分组的SQL语句有2个:

group by 和分组聚合函数实现 partition by (oracle和postgreSQL中的语句)功能

group by + having 组合赛选数据

注意:having 条件的字段必须在前面查询赛选存在,否则语法错误

错误格式:

SELECT MAX(ID),U_ID  FROM mlzm_comments GROUP BY U_ID HAVING Data_Status >0

正确格式:

SELECT MAX(ID),U_ID,Data_Status  FROM mlzm_comments GROUP BY U_ID HAVING Data_Status >0

group by强调的是一个整体,就是组,只能显示一个组里满足聚合函数的一条记录, partition by 在整体后更强调个体,能显示组里所有个体的记录。

#实际需求,获取满足条件第一条信息或最后一条信息

步骤拆解:

#步骤一:找出所有符合第一条件条件的数据,默认排序是按主键索引升序排列,这里按u_id 字段排序方便审阅

SELECT
a.ID,a.U_ID
FROM
mlzm_content a
WHERE
a.Data_Status = 2
ORDER BY a.U_ID,a.ID ASC;

#步骤2:利用group by 和max()、min()函数,对符合第一条件的数据进行分组,并获取当前分组中最小和最大的,注意当前结果集中的id字段不一定是最小的,若想要最小或最大id,需要对表a先进行排序处理

#未对表a 进行排序
SELECT
b.ID,b.U_ID,MIN(b.ID),MAX(b.ID)
FROM
(
SELECT
a.ID,a.U_ID
FROM
mlzm_content a
WHERE
a.Data_Status = 2
) AS b
GROUP BY b.U_ID;

上面的语句等效于

#优化处理,但这样的数据无法保证a.ID 排序的有效性
SELECT
a.ID,a.U_ID,MIN(a.ID),MAX(a.ID)
FROM
mlzm_content a
WHERE
a.Data_Status = 2
GROUP BY a.U_ID;

在这可以明确看出,所得的结果集中,当前的id 并非最小的也非最大的(如第1条显示的,当前id 为 31550 而最小的是 30768 最大的为38849),因此这种情况id字段不能作为后面的赛选条件

接下来用未排序的ID 字段作为依据查找的数据也并想要的

#以未排序的id字段作为参考依据,结果并非想要的
SELECTc.ID,c.U_ID,b.ID as b_id,b.U_ID as b_uid ,b.min_id,b.max_id
FROMmlzm_content AS c
INNER JOIN (SELECTa.ID,a.U_ID,MIN(a.ID) as min_id,MAX(a.ID) as max_idFROMmlzm_content as aWHERE a.Data_Status=2GROUP BYa.U_IDORDER BY a.U_ID
) AS b ON c.ID =b.ID

这种情况想要得到最小/最大的的一条信息,需要以min_id /max_id作为参考依据

#从未排序结果集中获取最小的一条信息
SELECTc.ID,c.U_ID,b.ID as b_id,b.U_ID as b_uid ,b.min_id,b.max_id
FROMmlzm_content AS c
INNER JOIN (SELECTa.ID,a.U_ID,MIN(a.ID) as min_id,MAX(a.ID) as max_idFROMmlzm_content as aWHERE a.Data_Status=2GROUP BYa.U_IDORDER BY a.U_ID
) AS b ON c.ID =b.min_id
#从未排序结果集中获取最大的一条信息
SELECTc.ID,c.U_ID,b.ID as b_id,b.U_ID as b_uid ,b.min_id,b.max_id
FROMmlzm_content AS c
INNER JOIN (SELECTa.ID,a.U_ID,MIN(a.ID) as min_id,MAX(a.ID) as max_idFROMmlzm_content as aWHERE a.Data_Status=2GROUP BYa.U_IDORDER BY a.U_ID
) AS b ON c.ID =b.max_id

最小的一条结果

耗时:0.0310 秒

最大的一条结果

先排序后再获取数据

#对表a 进行先排序处理
SELECT
b.ID,b.U_ID,MIN(b.ID),MAX(b.ID)
FROM
(
SELECT
a.ID,a.U_ID
FROM
mlzm_content a
WHERE
a.Data_Status = 2
ORDER BY a.ID ASC
) AS b
GROUP BY b.U_ID;

先进行排序后可以看出当前的id 和min(b.id)一致,现在可用id字段作为赛选条件

接下来用排序后得到的id 和min_id 来进行获取分组中最小的一条信息

#用排序后得到的id作为判断依据
SELECTd.ID,d.U_ID,c.ID AS c_id,c.U_ID AS c_uid,c.min_id,c.max_id
FROMmlzm_content AS d
INNER JOIN (SELECTb.ID,b.U_ID,MIN(b.ID) AS min_id,MAX(b.ID) AS max_idFROM(SELECTa.ID,a.U_IDFROMmlzm_content aWHEREa.Data_Status = 2ORDER BYa.ID ASC) AS bGROUP BYb.U_ID
) AS c ON d.ID = c.ID#用min_id 作为依据
SELECTd.ID,d.U_ID,c.ID AS c_id,c.U_ID AS c_uid,c.min_id,c.max_id
FROMmlzm_content AS d
INNER JOIN (SELECTb.ID,b.U_ID,MIN(b.ID) AS min_id,MAX(b.ID) AS max_idFROM(SELECTa.ID,a.U_IDFROMmlzm_content aWHEREa.Data_Status = 2ORDER BYa.ID ASC) AS bGROUP BYb.U_ID
) AS c ON d.ID = c.min_id

得到的结果集相同,因此先排序处理后id是可作为判断依据的否则只能用min_id作为判断依据

耗时:0.0410 秒

结论:先进行排序处理,关键字段可做判断依据,否则需要用获取的max(column_name)或min(column_name)作为判断依据。

但先进行排序会比不排序耗费的时间多,因此排序直接使用max(column_name)或min(column_name)作为判断依据处理要高效点。

错误的筛选方式:

#该方式判断是错误的,因为 结果集b中并未进行条件赛选,因此的到的结果中的min_id 对应的数据可能并不满足Data_Status=2的条件,最后做判断的时候这些数据会被排除掉。
SELECTc.ID,c.U_ID,b.ID as b_id,b.U_ID as b_uid ,b.min_id,b.max_id
FROMmlzm_content AS c
INNER JOIN (SELECTa.ID,a.U_ID,MIN(a.ID) as min_id,MAX(a.ID) as max_idFROMmlzm_content as aGROUP BYa.U_ID
) AS b ON c.ID =b.min_id  WHERE c.Data_Status=2
这是错误的判断方式,谨记啊

这样得到的结果集要少于真实的数据集。

除了(INNER) JOIN 外也可通过 in 和 exists 来获取

#用in 方式
SELECTc.ID,c.U_ID
FROMmlzm_content AS c
WHERE
c.ID in
(SELECTMIN(a.ID) as min_idFROMmlzm_content as aWHERE a.Data_Status=2GROUP BYa.U_ID
)
ORDER BY U_ID

耗时:0.0410 秒

#用exists 方式获取
SELECTc.ID,c.U_ID
FROMmlzm_content AS c
WHERE
exists
(
SELECT * from (SELECTMIN(a.ID) as min_idFROMmlzm_content as aWHERE a.Data_Status=2  GROUP BYa.U_ID
) as b  where b.min_id = c.ID
)
ORDER BY U_ID

耗时:0.0520 秒

小结:

in 和 exists 执行效率收 子表大小的影响,子表小in的效率高,反之,若子表大则exists的效率高。

in和exists效率比 join 低,因为只有1个字段判断,特别是在数据量大的时候差距更大,10万数据+的话 join 和 in至少差距在5分钟以上,因此最佳方式是使用INNER JOIN 连表查询

//=====================================================================================================//

获取满足条件的最小一条数据或最大一条数据,sql优化后:

最小:

SELECTc.*
FROMmlzm_content AS c
INNER JOIN (SELECTMIN(a.id) as min_idFROM aWHERE a.status=2 (条件判断)GROUP BY a.U_ID  (分组依据)
) AS b ON c.id =b.min_id
where (其他条件)

最大:

SELECTc.*
FROMmlzm_content AS c
INNER JOIN (SELECTmax(a.id) as max_idFROM aWHERE a.status=2 (条件判断)GROUP BY a.U_ID  (分组依据)
) AS b ON c.id =b.max_id
where (其他条件)

//=====================================================================================================//

上面利用group by分组方式 只能获取到最大或最小的,那么若是想要获取到指定位置的条数呢?如,获取满足条件的第5 条信息。

mysql中是不存在聚合函数 partition by的 ,要想实现类似功能需要利用 group_concat + substr等函数处理

partition by 语法

select .... over( partition by column1 order by column2)  from table_name ...

函数:

  concat(str1, str2,...)

  功能:将多个字符串连接成一个字符串

  结果:返回的结果为参数相连接产生的字符串,注意,若其中任意参数为null,则返回的结果也为null

  concat('str1','、 ','str2','、','str3')  对应的结果为:str1、str2、str3,但这样每次都要填写分隔符,看起来很是臃肿,那有没有简单的实现方式呢?

  有那就是concat_ws(separator, str1, str2, ...)函数(concat_ws就是concat with separator),功能与concat类似将多个字符串连接成一个字符串,但是可以一次性指定分隔符。

  上面的代码可简化为concat_ws('、','str1', 'str2', 'str3')

  注意:concat()和concat_ws()一样,只要传入的参数有null 则返回结果均为null,分隔符为null也是一样的。

  group_concat(expr[表达式])聚合函数 ,

  前言:在有group by的查询语句中,select指定的字段要么就包含在group by语句的后面,作为分组的依据,要么就包含在聚合函数中。(有关group by的知识:浅析SQL中Group By的使用)。

  group_concat()函数

  1、功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。

  2、语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc  ] [separator '分隔符'] )

  说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。

SELECTGROUP_CONCAT(a.ID)as ids,a.U_ID
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
ORDER BY a.U_ID 

将id倒序连接

# 以'# #'  来分割连接
SELECTGROUP_CONCAT(DISTINCT a.ID ORDER BY a.id DESC separator '# #')as ids,a.U_ID
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
ORDER BY a.U_ID 

接下来用substring_index(“待截取有用部分的字符串”,“截取数据依据的字符(分隔符)”,截取字符的位置N)函数来截取想要的数据

如:获取满足条件的前5 条信息

SELECTsubstring_index(GROUP_CONCAT(DISTINCT a.ID ORDER BY a.id ASC separator ','),',',5) as sub_id,a.U_ID
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
ORDER BY a.U_ID 

错误的获取(in):

SELECT c.id,c.U_ID FROM mlzm_content as c
JOIN
(SELECTsubstring_index(GROUP_CONCAT(DISTINCT a.ID ORDER BY a.id ASC separator ','),',',5) as sub_id,a.u_id
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
) as t
ON c.u_id = t.u_id
WHERE c.id in (t.sub_id)
ORDER BY c.u_id

可以看出in操作只匹配了第一个元素。若想要用in 操作的话可把子查询的结果集提出来再当做参数传入,如用PHP 中拆成2步来进行,先通过substring_index()函数把满足条件的数据先筛选出来,再通过结果集去循环查询匹配的数据,但是这样效率低,占用资源多,(因此舍弃这种操作)

正确的获取(find_in_set):

SELECT c.id,c.u_id FROM mlzm_content as c
JOIN
(SELECTsubstring_index(GROUP_CONCAT(DISTINCT a.ID ORDER BY a.id ASC separator ','),',',5) as sub_id,a.u_id
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
) as t
ON c.u_id = t.u_id
WHERE FIND_IN_SET(c.id,t.sub_id)
ORDER BY c.u_id

若是想得到前5条信息中最后一条信息

SELECT c.id,c.U_ID FROM mlzm_content as c
JOIN
(SELECTsubstring_index(substring_index(GROUP_CONCAT(DISTINCT a.ID ORDER BY a.id ASC separator ','),',',5),',',-1) as sub_id,a.U_ID
FROMmlzm_content AS a
WHEREa.Data_Status = 2
GROUP BYa.U_ID
) as t
ON c.id = t.sub_id 

利用这个方案, 以下类似业务需求都可以这么做, 如:

1. 查找每个用户过去10个的登陆IP

2. 查找每个班级中总分最高的两个人

greatest(value1,value2,...)函数,获取传入参数中最大的值

SELECT greatest(1,2,3,4)

SELECT greatest('a','b','c','bb','ae','d')

SELECT greatest('a','b','c','bb','ae','d'),ASCII('a'),ASCII('b'),ASCII('c'),ASCII('bb'),ASCII('ae'),ASCII('d')

从上面可以看出,greatest()函数在字符比较的时候,只取第一个字符进行ASCII 值比较

mysql group by 分组查询相关推荐

  1. java中mysql分组查询_ES对应mysql的group by分组查询javaApi,多对多关系的分组查询...

    ES对应mysql的group by分组查询javaApi,多对多关系的分组查询 比如我这边有个下列订单索引数据,现在的需求是按用户(fmerchantId)和支付方式(fchannelId)进行分组 ...

  2. mysql按月份分组查询_mysql如何按月份分组查询

    mysql按月份分组查询的方法:根据format字符串格式化date值,语法为[DATE_FORMAT(date,format)],其中[%M ]为月的名字. mysql按月份分组查询的方法:sele ...

  3. 使用mysql语句进行分组查询

    使用mysql语句进行分组查询 1 作用 对整个数据表的某几个字段进行分组,然后通过分组函数得到我们想要的结果 2 如何用 2.1 只分一个组 2.1.1 本质 就是根据分组字段把整个表的数据分为几组 ...

  4. group by分组查询后排序

    group by分组查询后排序 如:分组查询 SELECT s.name name,COUNT(s.id) value FROM t_setmeal s,t_order o WHERE s.id=o. ...

  5. MySQL使用group by分组查询每组最新的一笔数据

    问题来源 今天遇到一个查询数据库数据的问题:要获取每个分组最新的一笔数据,并将每个分组最新的一笔数据重新组成一个新的列表 这种场景,当然是想到了分组查询,使用 group by,思路也很清晰: 将所有 ...

  6. 9、使用GROUP BY分组查询

    在 MySQL 中,GROUP BY 关键字可以根据一个或多个字段对查询结果进行分组. 使用 GROUP BY 关键字的语法格式如下: GROUP BY <字段名> 其中,"字段 ...

  7. 2020-09-10 MYSQL按时间段分组查询当天,每小时,15分钟数据分组

    查询的需求比较麻烦,根据spreader_id和返回的状态码来判断事件的回传成功率,但是还需要新增时间段的查询,比如产品要的是每15分钟内数据的回传成功率. 这样的话就需要对时间段进行分组查询,我保存 ...

  8. mysql数据库如何分组查询_数据库MySQL--分组查询

    分组数据:group by 子句 分组查询语法: select 分组函数,列(要求是出现在group by的后面) from 表 (where 筛选条件)  # where 必须连接from关键字 g ...

  9. 都是MyBatis分页工具PageHelper惹的祸 —— 记一次加入GROUP BY分组查询成功,不分组则失败的奇怪现象Debug过程

    项目技术框架 请您打开世界上最好使的Java编译器IntelliJ IDEA,建一个SpringBoot项目,保证项目中包含以下依赖: 后端框架:SpringBoot + JUnit 数据库持久化:M ...

最新文章

  1. 手动创建Spring项目 Spring framework
  2. 2015-10-11 Sunday 晴 ARM学习
  3. 西南石油大学计算机科学院信息,梁宗文 - 西南石油大学 - 计算机科学学院
  4. Mac本地生成SSHKey的方法
  5. ServletContext_概述
  6. shell下将文件中的分隔符从‘\t‘转换成‘,‘
  7. AX2012 学习自动生成编码
  8. 【基础】算法时空复杂度【OI缩水版】
  9. AJAX学习笔记 一:简单的XMLHTTPRequest示例和asp.net异步更新。
  10. sony笔记本触摸板角落轻敲功能
  11. 深度学习入门(一)——深度学习如何入门?
  12. 【Unity3D日常开发】Unity3D中数字网格类游戏Demo实现
  13. 游戏中的网络同步机制——Lockstep
  14. 408 操作系统 知识点总结
  15. Mean Rank 和Mean reciprocal rank
  16. 水浒歪传--郭德纲相声
  17. 【金猿信创展】数新网络——国内云数智操作系统信创领导者
  18. LDO上电瞬间微过冲问题解决和讨论
  19. java打开浏览器_Java调用浏览器打开网页完整实例
  20. 三分钟认知Softmax和Sigmoid的详细区别

热门文章

  1. Java EE WEB工程师培训-JDBC+Servlet+JSP整合开发之13.Form表单处理(1)
  2. Kubernetes — CNI 规范
  3. jlink的SWD与JTAG下载模式的对应接线方法
  4. GD32的flash读、擦除、写操作
  5. 001-测试用例简介
  6. DataGridView控件60招(一)
  7. Android :数据库
  8. Jfinal 2.1 集成 Guice,实现注解功能, 加入Service接口和实现类,直接晒代码
  9. Merge Intervals
  10. React.js再探(四)