1. 程式人生 > >Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre

Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre

理解 出現 sco res ima 保存 engine .cn ict

原文鏈接: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:

idgroup_idnamescore
1 A 小剛 20
2 B 小明 19
3 B 小花 17
4 C 小紅 18

執行sql:
select name, group_id from game group by group_id

(記為sql_make_group)
返回:

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

解決方法

  1. 把group by字段group_id設成primary key 或者 unique NOT NULL。這個方法在實際操作中沒什麽意義。

  2. 使用函數any_value把報錯的字段name包含起來。如,select any_value(name), group_id from game group by group_id

  3. 在配置文件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

執行成功後,返回結果應該是

namegroup_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)

返回結果

namegroup_idscore
小明 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