MySqlでクエリを実行するときのonly_full_group_byに関連するエラー


442

私はシステムをアップグレードし、作業中のWebアプリケーション用にMySql 5.7.9とphpをインストールしました。動的に作成されるクエリがあります。古いバージョンのMySqlで実行すると、正常に機能します。5.7にアップグレードしてから、次のエラーが発生します。

SELECTリストの式#1がGROUP BY句になく、GROUP BY句の列に機能的に依存しない非集計列 'support_desk.mod_users_groups.group_id'が含まれています。これはsql_mode = only_full_group_byと互換性がありません

サーバーSQLモードのトピックに関するMysql 5.7のマニュアルページに注意してください。

これは私に問題を引き起こしているクエリです:

SELECT mod_users_groups.group_id AS 'value', 
       group_name AS 'text' 
FROM mod_users_groups
LEFT JOIN mod_users_data ON mod_users_groups.group_id = mod_users_data.group_id 
WHERE  mod_users_groups.active = 1 
  AND mod_users_groups.department_id = 1 
  AND mod_users_groups.manage_work_orders = 1 
  AND group_name != 'root' 
  AND group_name != 'superuser' 
GROUP BY group_name 
HAVING COUNT(`user_id`) > 0 
ORDER BY group_name

問題についてグーグルで調べましたがonly_full_group_by、クエリを修正するために何をする必要があるのか理解できません。only_full_group_byオプションをオフにすることはできますか、それとも他に何かする必要がありますか?

さらに情報が必要な場合はお知らせください。


ここで私はソリューションを見つけましたstackoverflow.com/a/7588442/612987
Wasim A.

21
これは、私が遭遇した中で最も複雑なエラーメッセージである必要があります。
Rolf

2
@Rolf Oracleで同じタイプの問題のエラーを見たことがありますか?「not a GROUP BY expressionそれだけです。数値のエラーコードがあり、メッセージがまったくない場合もあります。
ビルカーウィン、

回答:


359

に追加group_idしますGROUP BY

SELECT一部ではない列を使用する場合GROUP BY、グループ内のその列には複数の値が存在する可能性がありますが、結果には単一の値のスペースしかありません。したがって、通常、データベース、これらの複数の値を1つの値にする方法を正確に伝える必要があります。一般的に、これはのような集約関数で行われCOUNT()SUM()MAX()等...私が言う通常、他のほとんどの一般的なデータベース・システムは、この主張ので。ただし、バージョン5.7より前のMySQLでは、文句を言わずに任意の値を選択するため、デフォルトの動作はより寛容でした。また、ANY_VALUE()以前と同じ動作が本当に必要な場合に、この質問の別の解決策として使用できる関数。この柔軟性は非決定的であるためコストがかかります。そのため、それを必要とする十分な理由がない限り、この柔軟性はお勧めしません。MySQLは現在only_full_group_by、正当な理由でデフォルトで設定をオンにしているので、それに慣れてクエリをそれに準拠させるのが最善です。

では、なぜ上記の簡単な答えが返されるのでしょうか。私はいくつかの仮定をしました:

1)group_idはユニークです。妥当なようですが、結局それは「ID」です。

2)group_nameもユニークです。これはそのような合理的な仮定ではないかもしれません。これが当てはまらず、重複がある場合、group_names私のアドバイスに従ってに追加group_idするGROUP BYと、同じ名前のグループの結果に別の行が含まれるようになるため、以前よりも多くの結果が得られる場合があります。私は、データベースが任意の値を静かに選択しているため、これらの重複グループを非表示にするよりも優れています。

複数のテーブルが関係する場合は、すべての列をテーブル名またはエイリアスで修飾することもお勧めします...

SELECT 
  g.group_id AS 'value', 
  g.group_name AS 'text' 
FROM mod_users_groups g
LEFT JOIN mod_users_data d ON g.group_id = d.group_id 
WHERE g.active = 1 
  AND g.department_id = 1 
  AND g.manage_work_orders = 1 
  AND g.group_name != 'root' 
  AND g.group_name != 'superuser' 
GROUP BY 
  g.group_name, 
  g.group_id 
HAVING COUNT(d.user_id) > 0 
ORDER BY g.group_name

ありがとうございます。また、カラムを修飾する必要があることにも同意します。あいまいさの可能性を排除します。現在、コードを修復しています。助けてくれた100万人に感謝します。
Dan Bemowski、2015

GROUP BYクエリに句もありませんが、このエラーが発生しています。
aitchkhan 2017

@HaroonKhan、それは新しい質問のように聞こえます。よろしければご連絡ください。確認させていただきます。
davmos 2017

2
MySQL 5.7では、クエリ内のすべての非集計フィールドがGROUP BYであることを要求するプロパティを設定しました。したがって、SELECT a、SUM(b)FROM tableのようなクエリです。フィールド「a」はGROUP BY内にある必要があることを意味します。したがって、GROUP BYがない場合は、クエリに追加する必要があります。クエリのSELECT部分​​に少なくとも1つの集計フィールドがあるかどうかがすべてです。
user1567291

sql_modeの修正を提案するどの回答も機能しなかったため、この回答で提案されているようにgroup by句に項目を追加して「警告」を修正する必要がありました。(私のMySQLはストアドプロシージャに含まれていましたが、それが関連していたかどうかはわかりません)
zzapper 2018

354

only_full_group_by次のコマンドを実行すると、設定を無効にできます。

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

MySQL 8は受け入れないNO_AUTO_CREATE_USERため、削除する必要があります。


85
これは、作業の周りにある、あなたがより良いあなたのクエリではなく、警告のサイレンシングを修正
azerafati

1
/etc/mysql/my.cnf(下記参照)の更新は、デフォルト設定が再起動後に戻る傾向があるため、より持続可能なソリューションです。そして、クエリを修正する必要があると言う人にとっては、クイックデバッグクエリが必要で、SELECT COUNT(*), t.* FROM my_table t GROUP BY col20〜50列ある場合に、それが非常に簡単ではない場合、各列をグループ化?
Shadoweb

3
この「解決策」は非常に危険です。問題の設定フラグを1つだけ削除するのではなく、盲目的に変更することで、以前に無効にしたモードをアクティブ化できます。これにより、予期しない動作が発生したり、最悪の場合、誤った結果が生じたり、アプリが完全に機能しなくなったりする可能性があります。したがって、私はこの答えを間違っていると考えています。
クリスS.

1
私は経由で私の現在のsql_modeを考え出すことでリフレッシュを通じて、これは永続化SELECT @@sql_mode;し、そこからのmy.cnfに結果を追加:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
wbharding

323

他の回答で説明されているように警告メッセージをオフにすることも、何が起こっているのかを理解し修正することもできます。

MySQL 5.7.5以降、デフォルトのSQLモードにはONLY_FULL_GROUP_BY含まれています。これは、行をグループ化し、そのグループから何かを選択する場合、その選択を行う行明示する必要があることを意味します。 Mysqlは、グループ内のどの行を探しているかを知る必要があります。これにより、2つのオプションが提供されます。

Mysqlは、グループ内のどの行を探しているかを知る必要があります。これにより、2つのオプションが提供されます。

  • グループステートメントに必要な列を追加することもできます。group by rect.color, rect.valueこれは、場合によっては必要なものになる可能性があります。そうしないと、希望しない可能性のある同じ色の重複した結果が返されます。
  • mysqlの集約関数を使用して、完全なリストのようにグループ内で探している行を示すこともできます。AVG() MIN() MAX()
  • そして最後にANY_VALUE()、グループ内のすべての結果が同じであることが確実な場合に使用できます。文書

25
MySQLがFIRST()メソッド/関数をサポートしているとは思いませんか?
ベン・ギルド

3
MySQL(少なくとも5.7より前のバージョン)は、デフォルトでグループ内で最初に見つかった値を取ると思います。したがって、これはGROUP BY関数自体と同義であったため、FIRST()はありません。
DrDamnit 2016

2
@DrDamnit、それは混乱をONLY_FULL_GROUP_BY
引き起こし

6
私はすでに答えを知っていましたが、色付きの長方形の例はとても理解しやすいので、次回誰かが私に尋ねたときにそれを再利用します。
user327961 2016

@azerafatiには、FIRST()のようなものや、私と同じように最初の値を取得するために使用できるクエリがあります。
ハリス

169

現在のクエリを変更したくない場合は、以下の手順に従ってください-

  1. あなたのボックスに浮浪者のssh
  2. タイプ: sudo vim /etc/mysql/my.cnf
  3. ファイルの一番下までスクロールし、A入力して挿入モードに入ります
  4. コピーアンドペースト

    [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
  5. esc入力モードを終了するには、タイプしてください

  6. 入力:wqしてvimを保存して閉じます。
  7. sudo service mysql restartMySQLを再起動するために入力します。

これをAdonisJSで使用しようとするすべてのVagrantユーザーに向けて、paginate関数を実行するためにこれが必要です。
マイケルJ.カルキンス

これは明らかにVagrantユーザーだけでなく、あらゆるUnixシステムに当てはまります。私にとって、my.cnfファイルの場所はであったことに注意してください/etc。Alsはそれ以降の新しい構文に注意しますMySQL 5.7.8: sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
ValentinGrégoireOct

ミント19.3で私の作品(Ubuntuの18.04)感謝
マルコ・ロペス

71

ANY_VALUE()非集計列を参照するために使用します。

SELECT name,           address , MAX(age) FROM t GROUP BY name; -- fails
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name; -- works

MySQL 5.7 docsから:

ONLY_FULL_GROUP_BY を使用ANY_VALUE()して非集計列を参照することにより、無効にすることなく同じ効果を得ることができます。

...

ONLY_FULL_GROUP_BY選択リストの非集約アドレス列がGROUP BY句で指定されていないため、このクエリは有効になっていると無効になる場合があります。

SELECT name, address, MAX(age) FROM t GROUP BY name;

...

特定のデータセットについて、各名前の値が実際にアドレス値を一意に決定することがわかっている場合、アドレスは機能的に名前に依存しています。MySQLにクエリを受け入れるように指示するには、次のANY_VALUE()関数を使用できます。

SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;

1
しばらくこの問題に遭遇していた人として-MySQLの設定でファイルや設定を変更する必要がないため、このソリューションが特に好きです。興味深いことにANY_VALUE 、同様のディスカッションで他のどこにも言及されていません-私のGROUP_BY contains nonaggregated columnエラーで完璧に動作します。
adstwlearn

50

このエラーについて説明します。
MySQL 5.7.5以降、オプションONLY_FULL_GROUP_BYはデフォルトで有効になっています。
したがって、標準SQL92以前によると、

選択リスト、HAVING条件、またはORDER BYリストが、GROUP BY句で指定されておらず、GROUP BY列に機能的に依存していない(一意に決定されていない)非集計列を参照するクエリは許可されません。

ドキュメントで詳細を読む

したがって、たとえば:

SELECT * FROM `users` GROUP BY `name`;

上記のクエリを実行すると、エラーメッセージが表示されます。

#1055-SELECTリストの式#1がGROUP BY句になく、GROUP BY句の列に機能的に依存しない非集計列 'testsite.user.id'が含まれています。これはsql_mode = only_full_group_byと互換性がありません

どうして?
MySQLは正確に理解しないため、グループ化されたレコードから取得する特定の値と、これがポイントです。

IEでは、usersテーブルに次のレコードがあるとします。
よ

上記の無効なクエリを実行します。
そして、上記のエラーが表示されます。Johnこれは、nameのレコードが3つあり、それはすばらしいことですが、すべてのレコードに異なるemailフィールド値があるためです。
そのため、MySQLは、結果としてグループ化されたレコードでそれらのどれを返すかを単に理解していません。

この問題は、次のようにクエリを変更するだけで修正できます。

SELECT `name` FROM `users` GROUP BY `name`

また、SELECTセクションにさらにフィールドを追加することもできますが、それらが集約されていない場合は追加できませんが、使用できる松葉杖があります(ただし、あまりお勧めしません)。

SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`

ここに画像の説明を入力してください

さて、あなたは尋ねるかもしれません、なぜ使用ANY_VALUEが強く推奨されていませんか?
MySQLは、グループ化されたレコードのどの値を取得するかを正確に認識していないため、この関数を使用して、それらのいずれかをフェッチするように要求します(この場合、名前がJohnの最初のレコードの電子メールがフェッチされました)。
正確に私はなぜあなたがこの振る舞いを存在させたいのかについての考えを思いつくことができません。

MySQLのグループ化がどのように機能するかについて、私を理解していない場合は、非常に簡単です。

そして最後に、もう1つの単純でありながら有効なクエリを示します。
利用可能な年齢に応じて総ユーザー数をクエリする場合は、このクエリを書き留めることができます

SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;

MySQLのルールによると、これは完全に有効です。
等々。

問題が正確に何であるかを理解してから、解決策を書き留めることが重要です。


この素敵な答えをありがとう。結果グループの配列としてメールも必要な場合はどうなりますか?
ジョサイア

1
常にGROUP_CONCAT必須フィールドを使用して、そこにあるすべてのエントリを取得できます。
アブラハムトゥガロフ2017

ああ!だから方法があります!この質問で
ジョサイア

この素晴らしい答えをありがとう。私がやりたい場合はどうなりますGROUP BY DAY(created_date)か?DAY()追加すると動作しないようです。
エスキモー2018年

41

私はLaravel 5.3(mysql 5.7.12)をlaravel homestead(0.5.0と思います)で使用しています

/etc/mysql/my.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

それでもエラーが発生しました。

からに変更する必要config/database.phpがありtrueましたfalse

    'mysql' => [
        'strict' => false, //behave like 5.6
        //'strict' => true //behave like 5.7
    ], 

参考文献:

https://laracasts.com/discuss/channels/servers/set-set-sql-mode-on-homestead https://mattstauffer.co/blog/strict-mode-and-other-mysql-customizations-in-laravel -5-2


ダン!これはLaravelユーザーにとって役立ちました。+1。
Okafor T Kosiso

20

wamp 3.0.6または安定版2.5以外の上位バージョンを使用している場合、この問題に直面する可能性があります。まず、問題はsqlにあります。それに応じてフィールドに名前を付ける必要があります。しかし、それを解決する別の方法があります。ワンプの緑色のアイコンをクリックします。mysql-> mysql設定-> sql_mode->なし。または、コンソールからデフォルト値を変更できます。

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

素晴らしい、彼の言ったことに基づいて構築しshow variables like '%sql_mode%';、mysqlコマンドラインにコマンドを挿入、sql_mode設定が公開される
Jade Han

19

ファイルへの行の追加(下記の記述):/etc/mysql/my.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

私にとってはうまくいきます。サーバーのバージョン:5.7.18-0ubuntu0.16.04.1-(Ubuntu)


1
RDSを使用していますか?
Mubasshir Pawle 2017

@MubasshirPawle No
Jagdeep Singh 2017

16

mysqlまたはphpmyadminに移動してデータベースを選択し、このクエリを実行するだけで機能します。私にとってはうまくいきます。

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

Great..Thank :)
mohitesachin217

私の喜び:) @mohit
Anil Gupta

おかげで、時間を大幅に節約できました。
JoeRaid

1
ようこそ仲間@TharinduEranga
Anil Gupta

1
しかし、ソリューションの問題は、mysqlを再起動するたびにクエリを再度実行する必要があることです。これは、ソリューションが永続的でも永続的でもないことを意味します。
Mushfiqur Ra​​hman

10

Mac用:

1.デフォルトのmy-default.cnfを/etc/my.cnfにコピーします

sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf

2.お気に入りのエディターを使用してmy.cnfのsql_modeを変更し、これに設定します

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

3.MySQLサーバーを再起動します。

mysql.server restart

ありがとう、私のためにも働いた。しかし、私はmysqlのデフォルトのMacを使用しているので、brewパスがありません。sudo cp my-default.cnf /etc/my.cnf
Mike Nguyen

2
@Mike Nguyen sudo cp /usr/local/mysql-5.7.17-macos10.12-x86_64/support-files/my-default.cnf /etc/my.cnf sudo vi /etc/my.cnf set sql_model sql_mode = STRICT_TRANS_TABLES 、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、NO_ENGINE_SUBSTITUTION MySQLサーバーを再起動します。
Yong Gao

7

これが私が問題全体を理解するのに役立ったものです:

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

そして、次の別の問題のあるクエリの例で。

問題:

SELECT COUNT(*) as attempts, SUM(elapsed) as elapsedtotal, userid, timestamp, questionid, answerid, SUM(correct) as correct, elapsed, ipaddress FROM `gameplay`
                        WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY)
                        AND cookieid = #

これを最後に追加することで解決します:

  GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress

注:PHPのエラーメッセージを参照してください。問題の所在がわかります。

例:

MySQLクエリエラー1140:GROUP BYのない集約クエリでは、SELECTリストの式#4に非集約列 'db.gameplay.timestamp'が含まれています。これはsql_mode = only_full_group_byと互換性がありません-クエリ:試行としてのSELECT COUNT(*)、経過合計としてのSUM(elapsed)、ユーザーID、タイムスタンプ、質問ID、回答ID、正しいとしてのSUM(正しい)、経過、ipaddress FROMゲームプレイWHEREタイムスタンプ> = DATE_SUB (NOW()、INTERVAL 1 DAY)AND userid = 1

この場合、式#4がGROUP BYにありませんでした。



この問題を解決するための素晴らしい答え。どうもありがとうございました
Hansana Athukorala

7

localhost / wampserver 3の場合、sql-mode = user_modeを設定してこのエラーを削除できます。

click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode

WampまたはApacheを再起動します


1
私はこれがこの問題の長期的な修正ではないかもしれないことを知っていますが、確かに今のところ役に立ちました。私のホスティング会社であるGo DaddyはMySQL V5.6.33を使用しており、WampServer 3はMySQL V5.7.14を使用しています。このクイックフィックスソリューションをありがとう
アランN

4

あなたは追加することができますunique indexしますgroup_id。それgroup_idがユニークだと確信しているなら。

クエリを変更せずにケースを解決できます

遅い回答ですが、回答ではまだ言及されていません。多分それは利用可能な既に包括的な答えを完了するはずです。少なくとも、フィールドが多すぎるテーブルを分割しなければならなかった場合、私の問題は解決しました。


2

doctrineクエリビルダーを使用してSymfonyでこのエラーが発生し、このエラーがorderByによって発生した場合

目的selectの列に注意して、次の代わりにgroupBy使用します。addGroupBygroupBy

$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');

上の作品Symfony3 -


1

正確なSQLを使用しないことの謝罪

このクエリを使用して、Mysqlの警告を克服しました。

SELECT count(*) AS cnt, `regions_id`
FROM regionables 
WHERE `regionable_id` = '115' OR `regionable_id` = '714'
GROUP BY `regions_id`
HAVING cnt > 1

私の鍵に注意してください

count(*) AS cnt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.