记一次Group by 查询时的因MySQL版本不同出现的错误

本文介绍了如何解决MySQL 5.7及以上版本中因only_full_group_by规则导致的SQL查询错误。通过修改SQL语句使其符合规则、调整MySQL版本或关闭规则等方法进行解决。

前言:

在做项目的时候因为本地开发环境MySQL版本是5.5版本,而线上环境的MySQL版本是5.7.3版本的

我们要查询的SQL语句

--不规范的SQL语句(错误)
SELECT *,COUNT(1) AS COUNT FROM stepsrecord WHERE steps>1000 GROUP BY steps,uid HAVING COUNT>1;

在我们部署到线上环境的去访问的项目的时候报错了

Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘many_steps.stepsrecord.id’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

从字面意思理解是:select后面查询的字段没有出现在group by中。
MySQL在5.7.x版本以下是允许select后面的聚合函数出现未声明的字段(换句话来说就是select后面要查询的字段可以和group by 后面声明的字段不对应)

解决方案:

  1. 修改SQL语句使其遵守only_full_group_by规则(推荐使用)
 -- 举例说明:
 select a,b from table group by a,b,c; --(正确)
 select a,b,c from table group by a,b; --(错误)

所以我们要修改查询语句,使得前后一致就可以了。

 --不规范的SQL语句(错误)
 SELECT *,COUNT(1) AS COUNT FROM stepsrecord WHERE steps>1000 GROUP BY steps,uid HAVING COUNT>1;
 -- 规范的SQL语句(正确)
 SELECT steps,uid,COUNT(1) AS COUNT FROM stepsrecord WHERE steps>1000 GROUP BY steps,uid HAVING COUNT>1;
  1. 降级MySQL版本,使其版本小于5.7版本(不推荐)
    第一、现在mysql版本都已经8.0版本了,如果环境允许还是要向新版本靠拢,只要不断学习新的东西才能进步。
    第二、5.7版本only_full_group_by规则的出现就有其存在的意义,这里我们不做深究。
  2. 关闭only_full_group_by规则(不推荐)
    理由:我看网上很多解决办法都是这种,关闭其规则校验。不管是执行set sql_mode还是修改my.cnf文件都需要重启mysql服务。
    注意:如果使用set sql_mode关闭规则,重启mysql服务会重置规则,需要重新设置。
sql_mode 配置解析
  • 重点:ONLY_FULL_GROUP_BY
    对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中。简而言之,就是SELECT后面接的列必须被GROUP BY后面接的列所包含。如:
 -- 举例说明:
 select a,b from table group by a,b,c; --(正确)
 select a,b,c from table group by a,b; --(错误)
  • NO_AUTO_VALUE_ON_ZERO
    该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。(不信的可以试试,默认的sql_mode你在自增主键列设置为0,该字段会自动变为最新的自增值,效果和null一样),如果用户希望插入的值为0(不改变),该列又是自增长的,那么这个选项就有用了。

  • STRICT_TRANS_TABLES
    在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制。(InnoDB默认事务表,MyISAM默认非事务表;MySQL事务表支持将批处理当做一个完整的任务统一提交或回滚,即对包含在事务中的多条语句要么全执行,要么全部不执行。非事务表则不支持此种操作,批处理中的语句如果遇到错误,在错误前的语句执行成功,之后的则不执行;MySQL事务表有表锁与行锁非事务表则只有表锁)

  • NO_ZERO_IN_DATE
    在严格模式下,不允许日期和月份为零

  • NO_ZERO_DATE
    设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。

  • ERROR_FOR_DIVISION_BY_ZERO
    在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL

  • NO_AUTO_CREATE_USER
    禁止GRANT创建密码为空的用户

  • NO_ENGINE_SUBSTITUTION
    如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常

  • PIPES_AS_CONCAT
    将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似

  • ANSI_QUOTES
    启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符

感觉有用的同学,动动小手指给个赞,码字不易。

<think>好的,我现在需要回答用户的问题:“MySQL在进行查询,一个查询语句可可以多次使用group by?” 首先,我得确认用户的问题是什么。他们想知道是否可以在同一个SELECT语句中使用多个GROUP BY子句。 接下来,我需要回忆MySQL的语法规则。GROUP BY通常是在SELECT语句的最后部分,用于对结果集进行分组。但用户问的是是否可以多次使用,也就是在一个查询里出现多个GROUP BY。比如,是否允许类似这样的写法:SELECT ... GROUP BY ... GROUP BY ...? 根据已有的知识,标准的SQL语法中,每个SELECT语句只能有一个GROUP BY子句。如果在同一查询中使用多个,会导致语法错误过,可能存在一些特殊情况或不同的用法,比如在子查询中使用不同GROUP BY,或者在联合查询不同的部分各自使用GROUP BY。需要进一步确认这些情况。 然后,考虑用户可能的实际需求。用户可能想进行多级分组,或者在同一个查询中对不同字段进行分组,这候可能需要不同的方法,比如使用ROLLUP或者多个子查询。需要举出正确的例子来说明如何实现类似的效果,同指出直接多次使用GROUP BY允许的。 还需要检查是否有例外情况或MySQL特定的扩展允许这样的用法。查阅MySQL官方文档,确认GROUP BY的语法规定。根据文档,每个SELECT语句只能有一个GROUP BY子句,多次使用会导致错误。因此,直接在一个查询中写多个GROUP BY行的。 接下来,思考如何解释替代方案。例如,使用子查询中的GROUP BY,或者在UNION的不同部分各自使用GROUP BY。这样可以在一个查询中包含多个GROUP BY操作,但每个子查询或UNION分支只能有一个。 还要考虑用户的潜在错误理解,可能他们看到某些复杂查询中有多个分组,误以为可以多次使用GROUP BY。需要指出正确的做法,避免误解。 最后,总结回答的结构:明确回答允许,解释原因,提供替代方案,并给出示例。同提醒常见的错误和注意事项,确保用户能够正确应用。</think>--- ### 核心结论 **MySQL允许在同一个SELECT语句中直接多次使用GROUP BY子句**。每个查询块(包括子查询)只能包含一个GROUP BY分组操作。 --- ### 语法规则解析 1. **标准语法限制** ```sql -- 错误示例(语法错误SELECT department, COUNT(*) FROM employees GROUP BY department GROUP BY job_title; -- 第二个GROUP BY非法 ``` 2. **替代实现方案**(通过子查询分层处理): ```sql -- 先按部门分组统计,再按职位分组统计 SELECT job_title, COUNT(*) FROM ( SELECT department, job_title FROM employees GROUP BY department ) AS dept_group GROUP BY job_title; ``` --- ### 分层分组场景解决方案 #### 场景1:多维度统计(使用UNION ALL) ```sql -- 分别统计部门和职位的员工数 SELECT '部门维度' AS type, department, COUNT(*) FROM employees GROUP BY department UNION ALL SELECT '职位维度' AS type, job_title, COUNT(*) FROM employees GROUP BY job_title; ``` #### 场景2:多级嵌套统计(使用子查询) ```sql -- 先按部门统计,再按部门+职位统计 SELECT department, job_title, total FROM ( SELECT department, COUNT(*) AS total FROM employees GROUP BY department ) AS dept_stats JOIN ( SELECT department, job_title, COUNT(*) FROM employees GROUP BY department, job_title ) AS job_stats USING(department); ``` --- ### 高级分组技巧 1. **WITH ROLLUP扩展**(生成小计和总计): ```sql SELECT department, job_title, COUNT(*) FROM employees GROUP BY department, job_title WITH ROLLUP; ``` 2. **组合分组**(复合分组条件): ```sql -- 同按部门和职位分组 SELECT department, job_title, COUNT(*) FROM employees GROUP BY department, job_title; -- 单次GROUP BY多个字段 ``` --- ### 执行原理图示 ``` 原始数据表 第一次GROUP BY 第二次聚合操作 ┌─────┬───────────┐ ┌───────────┬────┐ ┌───────────┐ │部门 │ 职位 │ │ 部门 │数量│ │ 最终结果 │ ├─────┼───────────┤ ➔ ├───────────┼────┤ ➔ └───────────┘ │ HR │ 经理 │ │ HR │ 3 │ │ IT │ 工程师 │ │ IT │ 5 │ └─────┴───────────┘ └───────────┴────┘ ``` --- ### 常见错误示例 1. **直接重复使用**(立即报错): ```sql ERROR 1064 (42000): You have an error in your SQL syntax ``` 2. **错误嵌套尝试**: ```sql SELECT * FROM ( SELECT department, COUNT(*) FROM employees GROUP BY department ) GROUP BY department; -- 外层GROUP BY冗余 ``` --- ### 最佳实践建议 1. **复杂统计需求**: - 优先使用`GROUP BY 字段1, 字段2`进行组合分组 - 需要多维度统计使用UNION ALL拼接结果集 2. **性能优化方向**: ```sql -- 为分组字段建立复合索引 ALTER TABLE employees ADD INDEX idx_dept_job (department, job_title); ``` 通过合理设计分组策略,可以满足绝大多数业务场景的统计需求,同避免语法错误和性能问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值