mysql分组后,取每组第一条数据

简介 在工作中,有时候我们需要先group by之后,然后在获取group by之后的每组数据。这个时候sql怎么写呢?

在工作中,有时候我们需要先group by之后,然后在获取group by之后的每组数据。这个时候sql怎么写呢?

需求:

ef495ac5e164553778cbc8d12f6a5d7c.png

获取每本书的起始章节。比如:book_id为1的书籍的起始章节为:(1,2),book_id为2的起始章节为(1,3),这个时候怎么获取呢?

先看结论:

-- 倒叙
select * from (select distinct(a.id) tid, a.* from publish_book_chapter a
               where a.book_id in (1, 2)
              order by a.id desc) tt
group by tt.book_id;

-- 正序
select * from (select distinct(a.id) tid, a.* from publish_book_chapter a
               where a.book_id in (1, 2)
              order by a.id ) tt
group by tt.book_id;

思路:先进行排序,然后再进行分组,获取每组的第一条。


Q: 为什么要写distinct(a.id)呢?

A:防止合并的构造(derived_merge);


什么是derived_merge?

derived_merge指的是一种查询优化技术,作用就是把派生表合并到外部的查询中,提高数据检索的效率。这个特性在MySQL5.7版本中被引入,可以通过如下SQL语句进行查看/开启/关闭等操作。


上面虽然听起来感觉很牛逼的样子,但是实际情况是,这个新特性,不怎么受欢迎,容易引起错误。


可以在子查询中使用以下函数来进行关闭这个特性:

可以通过在子查询中使用任何阻止合并的构造来禁用合并,尽管这些构造对实现的影响并不明确。 防止合并的构造对于派生表和视图引用是相同的:
   1.聚合函数( SUM() , MIN() , MAX() , COUNT()等)
   2.DISTINCT
   3.GROUP BY
   4.HAVING
   5.LIMIT
   6.UNION或UNION ALL
   7.选择列表中的子查询
   8.分配给用户变量
   9.仅引用文字值(在这种情况下,没有基础表)

子查询order by失效的场景

d3d87ef492fa28d3864801073774657f.png


55cb05e9837470cccf5fb7ab956b7957.png

一旦外部表使用了group by,那么临时表(派生表 derived table)将不会执行filesort操作(即order by 会被忽略)。之后我使用了limit可以使其生效,原因是因为要使派生表order by生效,派生表可以通过使用group by、limit、having、distinct等等使其生效(方法有好多,详情可看文档https://dev.mysql.com/doc/refman/5.7/en/derived-table-optimization.html)


参考地址:


分组查询取每组最新的数据(order by 和group by使用问题):https://blog.csdn.net/weixin_41715751/article/details/102625795


mysql分组后获取每个组排序后的第一条数据(整行):https://blog.csdn.net/persistencegoing/article/details/92764058


Mysql取分组后的每组第一条数据:

https://www.cnblogs.com/hejw0413/p/12809959.html



来源:https://blog.csdn.net/u013066244/article/details/116461584?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-2-116461584.pc_agg_new_rank&utm_term=mysql+%E5%88%86%E7%BB%84%E5%90%8E%E6%AF%8F%E7%BB%84limit&spm=1000.2123.3001.4430

Top Top