Mysql基础(7)分组查询(group by子句)

本文详细介绍了SQL中的分组查询概念,包括基础分组查询、复杂分组查询以及按函数和多字段分组。通过实例解析了如何使用GROUP BY、HAVING子句以及WHERE子句进行数据筛选,强调了分组函数与HAVING子句在分组后筛选条件中的应用。此外,还讨论了分组查询在实际问题中的应用,如查询每个部门的最高工资、筛选特定条件下每个领导的最低工资等。

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

group by子句按照指定字段对数据表进行分组,使指定字段相同的数据行为一组。在此基础上,可以使用分组函数,对这些数据组进行组内统计,譬如统计某一个组的最大值、最小值等。group by关键字后的字段具有两个身份:其一是一般数据表字段(列名),其二是组的逻辑标识符(类似组名变量,代表一组数据)。

当字段充当组名变量时,分组函数和字段都包含’多‘的逻辑含义,进而可以逻辑对齐,因此两者可以同时出现在查询列表中。这即是分组函数只能和group by后的字段同时出现在查询列表中的原因。

其基本语法为

select 分组函数,列(要求出现在group by后面)
from 表名
[where字句]
group by 列名
[order by 字句]

基础分组查询

在写sql时,分析查询目标,找到识别词,然后转换到sql语境中,使用对应的sql子句。譬如 一般出现 ’每个XXX的统计维度‘ 时,这就涉及了一个分组统计的概念,可以使用group by子句。

基础分组查询是指可是在原始表的数据行中筛选,其的关键是分析查询目标,找到分组的依据,即所谓的组名,然后按照语法编写sql语句。

实例

#查询每个部门的最高工资
SELECT MAX(salary),job_id as 组名 FROM employees
 GROUP BY job_id  //前一个job_id可以理解为组名变量,即查询结果中 job_id列表示组名列。
# where子句在原始表的数据行中过滤commission_pct不为null
SELECT MAX(salary),manager_id FROM employees 
 WHERE `commission_pct` IS NOT NULL GROUP BY manager_id

复杂分组查询(having子句)

复杂分组查询是在分组之后,存在过滤条件,此时需要使用having子句。在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与聚合函数一起使用。

HAVING 子句可以让我们筛选分组后的各组数据。其基本步骤如下:

  1. 先进行基础分组查询
  2. 添加分组前筛选条件【where子句】,依据:在原数据表可查询
  3. 添加分组后筛选条件【having子句】,依据:只能在分组后的中间结果表中查到,多是分组函数结果

实例 查询领导编号 >102的每个领导手下员工的最低工资>5000的领导编号和最低工资。

#步骤1 确定查询目标、分组点 。存在 ‘每个’、‘最低’字样,则使用group by子句和分组函数
SELECT manager_id,MIN(salary) mm FROM employees GROUP BY manager_id 
#步骤2 添加where子句。领导编号在原数据表可查到,因此使用where子句
SELECT manager_id,MIN(salary) mm FROM employees WHERE manager_id > 102  GROUP BY manager_id 
#步骤3 添加havin子句 。最低工资 只能在分组后查询,因此使用having子句
SELECT manager_id,MIN(salary) mm FROM employees WHERE manager_id > 102 GROUP BY manager_id HAVING mm>5000 

按函数分组

函数j结果也可作为分组依据,即group by func()

实例 按员工姓名长度分组,查询每组的员工个数>5的员工个数

SELECT COUNT(*) cc,LENGTH(last_name) FROM employees GROUP BY LENGTH(last_name) HAVING cc >5

按多个字段分组

使用group by 字段1,字段2,字段N实现按多字段分组,mysql会将多个字段值都相等的数据行放置为一组。

假设按字段1,字段2分组,若第X行的字段1、字段2的值同第Y行的字段1、字段2的值相等,那么这两行数据会被分为一组。

实例 查询每个部门中每个工种的员工的平均工资

SELECT AVG(salary) ,department_id,job_id FROM employees GROUP BY department_id,job_id

对比

名称特点数据源关键字子句位置
基础分组查询分组前筛选字段在原始表中wheregroup by子句前面,from子句后
复杂分组查询分组后筛选字段在分组后的中间表havinggroup by子句后面

两个经验

  • 若分组函数作为筛选条件,其筛选条件一定是放在having子句中。

  • 优先考虑使用where子句,即分组前筛选。

    当字段在原始表中, where子句和having子句都可使用,这种情况优先使用where子句,提高性能。

    # 以下两种sql作用一致,优先使用第一种。
    SELECT manager_id,MIN(salary) mm FROM employees WHERE manager_id > 102  GROUP BY manager_id 
    SELECT manager_id,MIN(salary) mm FROM employees  GROUP BY manager_id HAVING manager_id > 102 
    
### Windows 10 上 MySQL 8.0 `GROUP BY` 查询问题及解决方案 在 Windows 10 环境下运行 MySQL 8.0 时,可能会遇到因 SQL 模式配置中的 `ONLY_FULL_GROUP_BY` 导致的 `GROUP BY` 查询异常。此问题是由于 MySQL 默认启用了严格模式 (`sql_mode`),其中包含了 `ONLY_FULL_GROUP_BY` 设置[^1]。 #### 问题描述 当执行带有 `GROUP BY` 子句的查询时,如果 `SELECT` 列表中存在未被聚合函数包裹且未出现在 `GROUP BY` 子句中的字段,则会触发错误提示。这是因为在启用 `ONLY_FULL_GROUP_BY` 后,MySQL 要求所有非聚合字段都必须显式声明于 `GROUP BY` 中,以遵循 SQL-92 标准[^3]。 例如,以下查询可能引发错误: ```sql SELECT column1, SUM(column2) FROM table_name GROUP BY column1; ``` 若 `column1` 并未参与任何聚合运算,而仅作为分组依据,则需将其加入到 `GROUP BY` 子句中,或者通过修改全局变量禁用该约束条件。 --- #### 解决方案一:调整查询逻辑 可以通过更改查询结构来满足 `ONLY_FULL_GROUP_BY` 的要求。具体做法如下: 将所有非聚合字段添加至 `GROUP BY` 子句中: ```sql SELECT column1, SUM(column2) AS total_column2 FROM table_name GROUP BY column1; ``` 如果需要保留原始行为并忽略多余字段的影响,可以利用聚合函数封装这些字段,比如使用 `MIN()` 或者 `MAX()` 函数: ```sql SELECT MIN(column1), SUM(column2) AS total_column2 FROM table_name GROUP BY column1; ``` 这种方法无需改动服务器端配置即可解决问题,推荐优先尝试这种方式[^4]。 --- #### 解决方案二:临时关闭 `ONLY_FULL_GROUP_BY` 可以在当前会话期间动态移除 `ONLY_FULL_GROUP_BY` 参数影响。执行以下命令可实现这一点: ```sql SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); ``` 这一步骤不会永久改变系统的默认设置,而是针对单次连接生效。适用于测试环境或短期调试场景下的快速修复需求[^2]。 --- #### 解决方案三:永久禁用 `ONLY_FULL_GROUP_BY` 为了彻底消除这一限制,可通过编辑 MySQL 配置文件 (my.ini/my.cnf),找到 `[mysqld]` 下面的相关条目,并重新定义 `sql_mode` 值。例如删除原有字符串内的 `"ONLY_FULL_GROUP_BY"` 组件后再保存重启服务程序完成应用更新过程: 打开 my.ini 文件定位到 [mysqld]: ```ini [mysqld] sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION" ``` 注意这里已经去掉了原来的 ONLY_FULL_GROUP_BY 定义项之后再启动 mysql server 即可恢复正常功能表现形式[^2]. 最后记得验证新的状态是否成功实施变更措施: ```sql SHOW VARIABLES LIKE 'sql_mode'; ``` --- ### 总结 以上三种方式分别对应不同层次的需求——从简单调整查询语句适应现有规则,到灵活控制特定客户端的行为直至全面解除限制均有所覆盖。用户可根据实际应用场景选取最合适的策略加以运用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值