Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre
原文鏈接:https://blog.csdn.net/hq091117/article/details/79065199
https://blog.csdn.net/allen_tsang/article/details/54892046
MySQL 5.7.5後only_full_group_by成為sql_mode的默認選項之一,這可能導致一些sql語句失效。
比如下表game:
id | group_id | name | score |
---|---|---|---|
1 | A | 小剛 | 20 |
2 | B | 小明 | 19 |
3 | B | 小花 | 17 |
4 | C | 小紅 | 18 |
執行sql:
select name, group_id from game group by group_id
返回:
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘game.name‘ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
解決方法
-
把group by字段
group_id
設成primary key 或者 unique NOT NULL。這個方法在實際操作中沒什麽意義。 -
使用函數
any_value
把報錯的字段name
包含起來。如,select any_value(name), group_id from game group by group_id
。 -
在配置文件my.cnf中關閉sql_mode=ONLY_FULL_GROUP_BY.。msqyl的默認配置是
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
ONLY_FULL_GROUP_BY
去掉,也可以去掉所有選項設置成sql_mode=
,如果你確信其他選項不會造成影響的話。
成功的步驟:
命令行打開mysql.cnf,可以用whereis查找
sudo vim /etc/mysql/conf.d/mysql.cnf
滾動到文件底部復制並粘貼
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
wq保存並退出
重啟MySQL
sudo service mysql restart
執行成功後,返回結果應該是
name | group_id |
---|---|
小剛 | A |
小明 | B |
小紅 | C |
為什麽默認設置ONLY_FULL_GROUP_BY限制?
對於上述的報錯信息,我的理解是select
字段裏包含了沒有被group by
條件唯一確定的字段name。
因為執行sql_make_group語句實際上把兩行紀錄小明
和小花
合並成一行,搜索引擎不知道該返回哪一條,所以認為這樣的sql是武斷的(arbitrary).
解決辦法2和3都是禁止檢查返回結果的唯一性。
進階討論
上述辦法可以解決報錯的問題,但也說明sql語句本身有邏輯問題。name
字段不應該出現在返回結果,因為它是不確定的。
考慮這樣的需求:按group_id
分組後,找出每組得分最少的人。
執行sql: select any_value(name) as name, group_id, min(score) as score from game group by group_id order by min(score)
返回結果
name | group_id | score |
---|---|---|
小明 | B | 17 |
小紅 | C | 18 |
小剛 | A | 20 |
B組的name
是小明
(因為小明
的id更小),而期望結果應該是小花
。
所以單純使用group by
無法實現這樣的需求。可以使用臨時表的方法:
select id, name,t.group_id, t.score from (select group_id, min(score) as score from game group by group_id order by min(score)) t inner join game on t.group_id=game.group_id and t.score=game.score
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre