17、MySQL的数据分组

group by

使用了group by, 就不必指定要计算和估值的每个组了、系统会自动生成
group by 必须出现在where字句之后,order by字句之前
1、创建分组:vend_id为描述字段,不能为计算字段,后面加上计算字段,group by后必须加上所有的描述字段

mysql> select vend_id, count(*) from products group by vend_id;
+---------+----------+
| vend_id | count(*) |
+---------+----------+
|    1001 |        3 |
|    1002 |        2 |
|    1003 |        7 |
|    1005 |        2 |
+---------+----------+

2、创建摘要with rollup

mysql> select vend_id, count(*) from products group by vend_id with rollup;
+---------+----------+
| vend_id | count(*) |
+---------+----------+
|    1001 |        3 |
|    1002 |        2 |
|    1003 |        7 |
|    1005 |        2 |
| NULL    |       14 |
+---------+----------+

3、分组过滤器 having

mysql> select vend_id, count(*) from products group by vend_id with rollup having count(*) > 2;
+---------+----------+
| vend_id | count(*) |
+---------+----------+
|    1001 |        3 |
|    1003 |        7 |
| NULL    |       14 |
+---------+----------+

4、分组和排序

mysql> select order_num, sum(quantity * item_price) from orderitems group by order_num;
+-----------+----------------------------+
| order_num | sum(quantity * item_price) |
+-----------+----------------------------+
|     20005 | 149.87                     |
|     20006 | 55.00                      |
|     20007 | 1000.00                    |
|     20008 | 125.00                     |
|     20009 | 38.47                      |
+-----------+----------------------------+
mysql> select order_num, sum(quantity * item_price) from orderitems group by order_num order by sum(quantity * item_price);
+-----------+----------------------------+
| order_num | sum(quantity * item_price) |
+-----------+----------------------------+
|     20009 | 38.47                      |
|     20006 | 55.00                      |
|     20008 | 125.00                     |
|     20005 | 149.87                     |
|     20007 | 1000.00                    |
+-----------+----------------------------+
mysql> select order_num, sum(quantity * item_price) from orderitems group by order_num having sum(quantity * item_price) > 100 order by sum(quantity * item_price);
+-----------+----------------------------+
| order_num | sum(quantity * item_price) |
+-----------+----------------------------+
|     20008 | 125.00                     |
|     20005 | 149.87                     |
|     20007 | 1000.00                    |
+-----------+----------------------------+

逆序+desc

mysql> select order_num, sum(quantity * item_price) as title from orderitems group by order_num having title > 100 order by title desc;
+-----------+---------+
| order_num | title   |
+-----------+---------+
|     20007 | 1000.00 |
|     20005 | 149.87  |
|     20008 | 125.00  |
+-----------+---------+

分组函数的执行顺序

select–>>from–>>where–>>group by–>>having–>>order by

<think> 我们正在讨论MySQL数据分组查询方法。根据引用内容,分组查询主要使用GROUP BY子句,并结合聚合函数或窗口函数来实现不同的分组需求。 用户的问题是如何获取数据分组,但根据引用内容,可以看到几种不同的分组应用场景: 1. 基础分组统计(引用[1]) 2. 分组内取最新一条记录(引用[2]) 3. 分组补全缺失数据(如24小时数据补0)(引用[3]) 因此,我将从以下几个方面回答: 1. 基本分组查询(GROUP BY + 聚合函数) 2. 使用窗口函数实现分组内排序取特定行 3. 分组数据补全(生成连续序列并左连接) 同时,根据引用[2]和[3]的示例,给出具体SQL写法。 注意:引用[2]中使用了窗口函数ROW_NUMBER(),需要MySQL8.0及以上版本。 下面开始组织回答: </think> ### MySQL数据分组查询方法详解 在MySQL中进行数据分组查询主要使用`GROUP BY`子句结合聚合函数实现,以下是具体方法和应用场景: --- #### 1. **基础分组统计** 使用`GROUP BY`配合聚合函数进行分组计算: ```sql -- 统计每个班级的学生人数 SELECT class_number, COUNT(*) AS student_count FROM student GROUP BY class_number; -- 计算每个订单的总金额 SELECT order_id, SUM(price * quantity) AS total_amount FROM order_details GROUP BY order_id; ``` **特点**: - 按指定列分组(可多列) - 必须配合聚合函数(`COUNT`, `SUM`, `AVG`, `MAX`, `MIN`) - 过滤分组结果可用`HAVING`子句[^1] --- #### 2. **分组取最新记录** **适用场景**:获取每个分组的最新一条数据(如最新订单状态) ```sql /* MySQL 8.0+ 窗口函数方案 */ SELECT * FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY class_number ORDER BY create_time DESC ) AS rn FROM student ) t WHERE rn = 1; ``` **说明**: - `PARTITION BY`:定义分组列 - `ORDER BY`:定义组内排序规则 - `ROW_NUMBER()`:为组内每条记录生成序号[^2] **兼容低版本方案**: ```sql SELECT s1.* FROM student s1 LEFT JOIN student s2 ON s1.class_number = s2.class_number AND s1.create_time < s2.create_time WHERE s2.id IS NULL; ``` --- #### 3. **分组数据补全** **适用场景**:缺失时间段数据补零(如24小时统计) ```sql -- 生成24小时序列并左连真实数据 SELECT a.hour, IFNULL(b.count, 0) AS count FROM ( SELECT 0 AS hour UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 -- ... 完整生成0-23小时序列 ) a LEFT JOIN ( SELECT HOUR(create_time) AS hour, COUNT(*) AS count FROM student WHERE DATE(create_time) = CURDATE() GROUP BY HOUR(create_time) ) b ON a.hour = b.hour ORDER BY a.hour; ``` **关键技术**: - 使用`UNION`生成连续序列 - `LEFT JOIN`保留所有时间点 - `IFNULL()`实现空值补零[^3] --- #### 4. **分组结果筛选** ```sql -- 筛选学生数超过30的班级 SELECT class_number, COUNT(*) AS cnt FROM student GROUP BY class_number HAVING cnt > 30; -- HAVING用于分组后筛选 -- 与WHERE对比(WHERE在分组前过滤) SELECT class_number, COUNT(*) AS cnt FROM student WHERE grade > 60 -- 先过滤及格学生 GROUP BY class_number; ``` --- ### 分组查询优化建议 1. **索引优化** 为分组列和排序列创建复合索引: ```sql CREATE INDEX idx_class_time ON student(class_number, create_time); ``` 2. **减少分组列数量** 避免`GROUP BY`包含过多列,增加计算复杂度 3. **分区表应用** 超大数据表可使用分区表提升性能: ```sql CREATE TABLE logs ( id INT, log_time DATETIME ) PARTITION BY RANGE (YEAR(log_time)) ( PARTITION p2020 VALUES LESS THAN (2021), PARTITION p2021 VALUES LESS THAN (2022) ); ``` --- ### 常见问题排查 **Q:错误代码1055 - GROUP BY失效** **原因**:MySQL 5.7+ 默认启用`ONLY_FULL_GROUP_BY` **解决**: ```sql -- 方案1:关闭严格模式(不推荐) SET sql_mode = ''; -- 方案2:正确使用聚合函数 SELECT class_number, MAX(student_name) FROM student GROUP BY class_number; ``` **Q:分组结果不符合预期** 检查点: 1. 分组列存在`NULL`值(NULL会被单独分组) 2. 字符集不一致导致分组异常 --- ### 相关问题延伸 1. 如何实现多级分组统计(如按年-月分组)? 2. 分组查询中`WITH ROLLUP`的用途是什么? 3. 窗口函数`RANK()`和`ROW_NUMBER()`有什么区别? 4. 如何优化大数据量分组的性能? [^1]: MySQL通过`GROUP BY`实现基础分组统计 [^2]: 使用窗口函数实现分组内取最新记录 [^3]: 通过序列生成和左连接补全分组数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值