mysql group by/having/distinct 查询使用例子

本文深入探讨了SQL查询中常用的操作,包括最高分查询、总分排名、平均分筛选等,通过具体实例展示了如何高效地从数据库中获取所需信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表的内容如下:

//查询单分数最高的人ID

select stuid,max(score) from stu_select_class;

// 查询各科总分2-3名的学生
select stuid, sum(score) from stu_select_class group by stuid  limit 1,2;

//查询每科的最高分学生
select classname,stuid,max(score) from stu_select_class group by classname;

//查询总分低于140的学生
select stuid, sum(score) from stu_select_class group by stuid having sum(score)<140;

//查询总平均分在60-80的学生
select stuid, avg(score) from stu_select_class group by stuid having avg(score) between 60 and 80;

//查询。。。。的学生
select stuid, sum(score),avg(score) from stu_select_class group by stuid having sum(score)<140 and avg(score) <80;
//查询总分。。的学生人数。
select distinct count( stuid)  from stu_select_class group by stuid having sum(score)<140 and avg(score) <80;
//查询。。。的学生人数
select count(distinct stuid) from stu_select_class where classname='english' and score <100;

<think>好的,我现在需要详细解释MySQL中的GROUP BYHAVING的作用及用法。首先,我得回忆一下用户之前的问题和我的回答,确保内容一致且不重复。用户提到要参考之前的引用,所以我得看看引用里的内容是否有帮助。 首先,GROUP BY的作用是对数据进行分组,通常和聚合函数一起使用,比如SUM、AVG等。引用[2]中提到的例子显示,当使用GROUP BY时,SELECT中的非聚合列必须出现在GROUP BY子句中,否则会报错。这说明GROUP BY的一个关键点是对非聚合字段的分组约束。 接下来是HAVING。用户之前的回答中提到,HAVING用于过滤分组后的数据,只能访问聚合后的结果或GROUP BY的列。引用[3]和[4]中的例子展示了HAVING后面跟聚合函数的条件,比如SUM(salary) > 400或者AVG(grade) >= 90。这说明HAVING的主要作用是对聚合后的结果进行筛选,而WHERE是在分组前对原始数据进行过滤。 需要比较WHERE和HAVING的区别,用户之前的问题也涉及这一点。WHERE在数据分组前应用,不能使用聚合函数;而HAVING在分组后使用,可以针对聚合值进行过滤。比如引用[3]中的例子,WHERE过滤salary>150后再分组,而HAVING过滤sum(salary)>400。 另外,关于执行顺序,之前的回答指出GROUP BY在WHERE之后,HAVINGGROUP BY之后。所以在处理时,先通过WHERE筛选数据,然后分组,最后用HAVING过滤分组结果。 还需要提到ONLY_FULL_GROUP_BY模式的影响,如引用[2]中的错误示例,当没有启用该模式时,MySQL可能允许SELECT中出现未在GROUP BY中的非聚合列,但结果可能不确定。启用该模式后,会强制要求所有非聚合列必须在GROUP BY中,否则报错。 性能方面,引用[2]提到了GROUP BY的性能考虑,比如分组的字段是否有索引,数据量大小等。合理使用索引可以提升分组查询的效率。 可能还需要给出正确和错误的示例,帮助用户理解。例如正确使用GROUP BYHAVING的SQL语句,以及常见错误如遗漏GROUP BY字段或错误使用HAVING条件。 最后,总结GROUP BYHAVING的常见用法、注意事项以及最佳实践,比如始终启用ONLY_FULL_GROUP_BY以保证数据一致性,合理选择分组字段,避免在HAVING使用非聚合字段等。 需要确保回答结构清晰,分点说明,结合示例和引用内容,同时回答用户可能的相关问题,比如执行顺序、错误处理、性能优化等。还要检查是否有遗漏的重要点,比如与DISTINCT的区别,或者HAVING使用别名的注意事项,根据之前的回答,MySQL允许HAVING使用SELECT中的别名,这是优化器的特性。</think>### MySQL 中 `GROUP BY` 和 `HAVING` 的作用及详细用法 #### 一、`GROUP BY` 的作用与用法 `GROUP BY` 用于将数据按指定列分组,通常与聚合函数(如 `SUM`、`AVG`、`COUNT` 等)结合使用,对分组后的数据进行统计分析。 ##### 1. **核心功能** - **分组统计**:将表中数据按指定列的值分组,对每组数据执行聚合计算。 示例:按部门分组计算平均工资 ```sql SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department; ``` - **约束非聚合字段**:在严格模式(`ONLY_FULL_GROUP_BY`)下,`SELECT` 中的非聚合字段必须出现在 `GROUP BY` 中,否则报错[^2]。 - **正确示例**(分组字段与 `SELECT` 字段一致): ```sql SELECT department, job_title, AVG(salary) FROM employees GROUP BY department, job_title; -- 分组字段包含所有非聚合列 ``` - **错误示例**(`job_title` 未在 `GROUP BY` 中): ```sql SELECT department, job_title, AVG(salary) -- 报错:job_title 未分组 FROM employees GROUP BY department; ``` ##### 2. **注意事项** - **性能优化**: - 若分组字段有索引,可加速分组操作。 - 避免对大表进行无索引分组,可能导致全表扫描,影响性能[^2]。 - **结果确定性**: 若未启用严格模式,MySQL 可能返回分组外的随机值(如未在 `GROUP BY` 中的字段),导致数据不可靠[^1]。 --- #### 二、`HAVING` 的作用与用法 `HAVING` 用于过滤 **分组后的数据**,与 `WHERE` 的区别在于: - `WHERE`:在分组前过滤原始数据,**不能使用聚合函数**。 - `HAVING`:在分组后过滤聚合结果,**必须引用聚合字段或分组列**。 ##### 1. **核心功能** - **过滤聚合结果**:筛选满足条件的分组。 示例:筛选平均工资大于 5000 的部门 ```sql SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department HAVING avg_salary > 5000; -- 直接使用 SELECT 别名 ``` - **支持复杂条件**:可组合聚合函数和逻辑运算符。 示例:筛选总工资超过 10 万且部门名称包含 "Sales" 的分组 ```sql SELECT department, SUM(salary) AS total_salary FROM employees GROUP BY department HAVING total_salary > 100000 AND department LIKE '%Sales%'; ``` ##### 2. **注意事项** - **作用域限制**: `HAVING` 只能访问 `GROUP BY` 中的列或聚合函数结果,若引用未分组的非聚合字段会触发错误(取决于 SQL 模式)[^1][^2]。 - **别名使用**: MySQL 允许在 `HAVING` 中使用 `SELECT` 中定义的别名(如 `avg_salary`),这是语法优化特性[^1][^2]。 --- #### 三、`GROUP BY` 与 `HAVING` 的执行顺序 MySQL查询逻辑遵循以下顺序: $$ \text{FROM} \rightarrow \text{WHERE} \rightarrow \text{GROUP BY} \rightarrow \text{HAVING} \rightarrow \text{SELECT} \rightarrow \text{ORDER BY} \rightarrow \text{LIMIT} $$ - **关键点**: - `WHERE` 在分组前过滤数据,减少分组计算量。 - `HAVING` 在分组后过滤,仅保留符合条件的分组。 **示例对比**: ```sql -- WHERE 过滤原始数据,HAVING 过滤分组结果 SELECT department, AVG(salary) AS avg_salary FROM employees WHERE hire_date > '2020-01-01' -- 先筛选入职GROUP BY department HAVING avg_salary > 8000; -- 再筛选平均工资 ``` --- #### 四、常见错误与解决方案 1. **非聚合字段未分组** **错误**:`SELECT` 包含未在 `GROUP BY` 中的非聚合字段。 **解决**: - 启用 `ONLY_FULL_GROUP_BY` 模式,强制所有非聚合字段分组。 - 使用 `ANY_VALUE()` 函数明确处理不确定字段: ```sql SELECT department, ANY_VALUE(job_title), AVG(salary) FROM employees GROUP BY department; ``` 2. **`HAVING` 中引用非聚合字段** **错误**:`HAVING` 条件包含未分组或未聚合的字段。 **解决**: - 将字段添加到 `GROUP BY` 中。 - 改用聚合函数(如 `MAX()`、`MIN()`)。 --- #### 五、最佳实践 1. **启用严格模式**: 始终开启 `ONLY_FULL_GROUP_BY` 以保证数据确定性: ```sql SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES'; ``` 2. **合理选择分组字段**: 仅对分析所需的维度分组,避免无意义分组降低性能。 3. **优先使用 `WHERE`**: 尽量在 `WHERE` 中提前过滤数据,减少分组计算量。 --- ### 示例场景 1. **统计每个部门的最高工资并筛选超过 1 万的部门** ```sql SELECT department, MAX(salary) AS max_salary FROM employees GROUP BY department HAVING max_salary > 10000; ``` 2. **按年份和月份分组统计订单数量,筛选订单数超过 100 的月份** ```sql SELECT YEAR(order_date) AS year, MONTH(order_date) AS month, COUNT(*) AS order_count FROM orders GROUP BY year, month HAVING order_count > 100; ``` --- ### 相关问题 1. **如何判断是否应该使用 `WHERE` 还是 `HAVING`?** - `WHERE` 用于过滤原始数据,`HAVING` 用于过滤分组后的聚合结果。例如,筛选“2023 年之后入职的员工”用 `WHERE`,筛选“部门平均工资大于 5000”用 `HAVING`。 2. **`GROUP BY` 是否支持多列分组?** - 是的,可以按多列分组,例如 `GROUP BY department, job_title`,此时分组依据是部门和职位的组合[^2]。 3. **`HAVING` 能否使用别名的聚合字段?** - 可以,如 `HAVING avg_salary > 5000`,MySQL 会解析别名对应的聚合表达式[^1][^2]。 --- 通过合理使用 `GROUP BY` 和 `HAVING`,可以高效完成复杂的数据分组与筛选需求,同时避免常见语法错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值