前两天同事有个 MySQL 数据分组的需求,如下测试数据,需要找出每个 name 分组中 create_date 最近的记录:
创新互联建站主要从事网页设计、PC网站建设(电脑版网站建设)、wap网站建设(手机版网站建设)、响应式网站开发、程序开发、网站优化、微网站、微信小程序等,凭借多年来在互联网的打拼,我们在互联网网站建设行业积累了丰富的成都做网站、网站制作、网站设计、网络营销经验,集策划、开发、设计、营销、管理等多方位专业化运作于一体。
需要注意的是,此处用的 MySQL 是5.6,最初是使用这条语句:
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select name, value, create_date, update_date from t1 group by name order by create_date desc; /pre
用这条 SQL 得到的其实只是每个 name 分组中最先插入的记录,然后按照 create_date 进行了降序排列,和原始需求,完全不同。
此时可采用分而治之的策略,先做排序,再做分组:
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select * from (select name, value, create_date, update_date from t1 order by create_date desc) t group by t.name; /pre
当然,针对此需求,可能有其他方法,有兴趣的朋友,可以尝试写写,共享一下。
可能有细心的朋友会发现个问题,就是上述 SQL 中的 group by ,好像有些奇怪,如果按照常规,select 中的字段需要出现在 group by 中,上述语句竟然没报错?
如果我们在 MySQL 5.7 执行相同的语句:
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select name, value, create_date, update_date from t1 group by name order by create_date desc; /pre
因此从5.6升级到5.7,很可能出现这种相同的 SQL 执行结果不同的现象,这对兼容性测试的要求就会很高,究其原因,一方面是特性决定的,另一方面就是各种配置参数不同导致的。
可以在5.7的 sql_mode 中删除这个 ONLY_FULL_GROUP_BY ,即可达到5.6相同效果了,或者改写 SQL ,例如:
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select * from t1 a where create_date = (select max(create_date) from t1 b where a.name = b.name); /pre
或者,
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select * from t1 a where not exists (select * from t1 b where a.name = b.name and b.create_date a.create_date); /pre
MySQL 8.0支持 row_number()函数,操作应该和如下 Oracle 相近的。
Oracle 中可以使用 row_number()实现此需求:
pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;" select * from (select name, create_date, row_number() over (partition by name order by create_date desc) as r from t1) where r=1; /pre
上一篇聚合函数末尾处使用了GROUP BY,但没有做具体的介绍,这一篇就主要介绍一下GROUP BY的使用方法。顺便介绍一下对分组查询的过滤关键词HAVING的用法。
在MySQL中,GROUP BY关键词可以根据一个或多个字段对查询结果进行分组,类似于Excel中的数据透视表。可以单独使用,但一般情况下都是结合聚合函数来使用的。
语法格式如下:
下面演示都是基于这一张简单的省份对应大区的表格。
【单独使用GROUP BY】
单独使用GROUP BY关键字时,查询结果会只显示每个分组的第一条记录。
根据省份表里面的大区进行聚合,查询全国共分成了几个大区,SQL语句如下↓
【GROUP BY结合聚合函数】
5个聚合函数上一篇已经详细介绍了用法,GROUP BY和聚合函数结合使用也是最频繁的,下面就继续使用省份表来求每个大区有多少个省份,对应的聚合函数就是COUNT函数,SQL语句如下↓
【GROUP BY结合GROUP_CONCAT】
这还是一个很有用的功能,GROUP_CONCAT() 函数会把每个分组的字段值都合并成一行显示出来。
下面继续使用省份表,把每个大区对应的省份放在一行展示,用分号分开,SQL语句如下↓
【GROUP BY结合WITH ROLLUP】
WITH POLLUP关键词用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,SQL语句如下↓
【GROUP BY结合HAVING】
在MySQL中,可以使用HAVING关键字对分组后的数据进行过滤。
使用 HAVING 关键字的语法格式如下:
HAVING关键词和WHERE关键词都可以用来过滤数据,且HAVING支持WHERE关键词中所有的操作符和语法。但是WHERE和HAVING关键字也存在以下几点差异:
下面筛选一下省份数量在7个及以上的大区,SQL语句如下↓
【GROUP BY结合ORDER BY】
聚合后的数据,一半情况下也是需要进行排序的,通过ORDER BY对聚合查询结果进行排序,对省份数量按从大到小进行排序,SQL语句如下↓
End
◆ PowerBI开场白
◆ Python高德地图可视化
◆ Python不规则条形图
如何分组数据,以便能汇总表内容的子集。这涉及两个新SELECT语句子句,分别是GROUP BY子句和HAVING子句。
分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
分组是在SELECT语句的GROUP BY 子句中建立的。
来看例子理解:
mysqlselect vend_id,COUNT(*) AS num_prods from products group by vend_id;
也就是不同的Id的商品总数都能分别查出来。
除了能用GROUP BY分组数据外,Mysql还允许过滤分组,规定包括哪些分组,排除哪些分组。
也就是HAVING子句。
mysqlselect cust_id,COUNT( /) AS orders from orders uGROUP BY/u cust_id uHAVING/u COUNT( /) =2;
注意:这里HAVING换成WHERE是不管用的。HAVING针对于分组。
WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。
那么咱么看看怎么混合WHERE和HAVING。
mysqlselect vend_id, COUNT( / ) AS num_prods from products uwhere prod_price=10 group by/u vend_id HAVING COUNT( /) =2;
mysqlselect order_num,SUM(quantity*item_price) AS ordertotal
from orderitems
GROUP BY order_num
HAVING SUM(quantity*item_price) =50
order by ordertotal;
/*语法:
select 分组函数 列(要求出现在group by的后面)
from 表
【where 筛选条件】
group by 分组的列表
[order by 子句]
注意:查询列表必须特殊,要求是分组函数和group by 后出现的字段
特点:
1.分组查询中筛选条件分为两类:
数据源 位置 关键字
分组前筛选 原始表 group by子句的前面 where
分组后筛选 分组后的结果集 group by子句的后面 having
1.分组函数做条件肯定是放在having子句中
2.能用分组前筛选的,优先考虑使用分组前筛选
2.group by 子句支持单个字段、多个字段分组(用逗号隔开没有顺序要求)表达式或函数(用的较少)
3.也可以添加排序(放在整个group by子句之后)
*/
count(1),其实就是计算一共有多少符合条件的行。
1并不是表示第一个字段,而是表示一个固定值。
其实就可以想成表中有这么一个字段,这个字段就是固定值1,count(1),就是计算一共有多少个1.
同理,count(2),也可以,得到的值完全一样,count('x'),count('y')都是可以的。一样的理解方式。在你这个语句理都可以使用,返回的值完全是一样的。就是计数。
count(*),执行时会把星号翻译成字段的具体名字,效果也是一样的,不过多了一个翻译的动作,比固定值的方式效率稍微低一些。
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款