web-dev-qa-db-ja.com

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

私は自分のシステムをアップグレードし、私が取り組んでいるウェブアプリケーションのためにphpでMySql 5.7.9をインストールしました。動的に作成されたクエリがあります。MySqlの古いバージョンで実行しても正常に動作します。 5.7にアップグレードしてから、私はこのエラーが出ます:

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

Server SQL Modes のトピックの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オプションをオフにするだけでいいですか、それとも他にやるべきことはありますか?

あなたがより多くの情報を必要とするならば私に知らせてください。

337
Dan Bemowski

group_idGROUP BYを追加するだけです。

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

それでは、なぜ私の簡単な答えは上のですか?私はいくつかの仮定をしました:

1)group_idは一意です。合理的に思えます、結局それは 'ID'です。

2)group_nameもユニークです。これはそのような合理的な仮定ではないかもしれません。そうではなく、いくつか重複するgroup_namesがあり、それからgroup_idGROUP 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
281
davmos

以下を実行して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を受け付けないため、削除する必要があります。

286
WeiYuan

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

MySQL 5.7.5以降、デフォルトのSQLモードにはONLY_FULL_GROUP_BYが含まれています。 これは、行をグループ化してそのグループから何かを選択する場合、明示的にどの行を指定する必要がありますから作られた。 Mysql needs to know which row in the group you're looking for, which gives you two options

Mysqlはあなたが探しているグループのどの行を知る必要があります。

  • また、必要な列をグループステートメントgroup by rect.color, rect.valueに追加することもできます。これは、場合によっては必要なものになる可能性があります。
  • mysqlのaggregate functionsを使用して、AVG()MIN()MAX()完全なリスト のようにグループ内で探している行を指定することもできます。
  • そして最後に、グループ内のすべての結果が同じであることが確実な場合は、ANY_VALUE()を使用できます。 doc
275
azerafati

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

  1. あなたのボックスにvagrant 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. Vimを保存して閉じるには:wqを入力してください。
  7. MySQLを再起動するにはSudo service mysql restartを入力します。
154
Ajai

非集約列を参照するには、ANY_VALUE()を使用します。

MySQL 5.7 docs :から

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

...

選択リストの集約されていない住所列がONLY_FULL_GROUP_BY節で名前が付けられていないため、この照会はGROUP BYが有効になっていると無効になる可能性があります。

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

...

特定のデータセットに対して、それぞれの名前の値が実際にアドレス値を一意に決定することを知っている場合、addressは事実上名前に依存します。 MySQLにクエリを受け付けるように指示するには、ANY_VALUE()関数を使用できます。

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

このエラーについて説明します。
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は正確には理解していないため、グループ化されたレコードから特定の値を取得する必要があります。これがポイントです。

I.E. usersテーブルにこのレコードがあるとしましょう。
Yo

そして上記の無効なクエリshowenを実行します。
そして上記のようなエラーになるでしょう。なぜなら、Johnという名前の3つのレコードがあり、それはNiceですが、それらはすべて異なるemailフィールド値を持っているからです。
そのため、MySQLは結果のグループ化されたレコードにどちらを返すかを単に理解していません。

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

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

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

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

enter image description here

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

MySQLのグループ化がどのように機能するかについて、私のことを理解していない場合はもっと読んでください、それは非常に簡単です。

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

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

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

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

41
Abraham Tugalov

私は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.phptrueから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-Homesteadhttps://mattstauffer.co/blog/strict-mode-and-その他のMySQLのカスタマイズ - 5 - 2

35
Ryan

あなたがwamp 3.0.6または安定版2.5以外のより高いバージョンを使っているなら、あなたはこの問題に直面するかもしれません、まず問題はsqlにあります。それに応じてフィールドに名前を付ける必要があります。しかしそれを解決することができる別の方法があります。沼の緑色のアイコンをクリックしてください。 mysql-> mysql設定 - > sql_mode-> none。またはコンソールからデフォルト値を変更できます。

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';
18
PiyaChakraborty

ファイル内の行の追加(後述):/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)

13
Jagdeep Singh

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
9

Localhost/wampserver 3では、このエラーを取り除くためにsql-mode = user_modeを設定することができます。

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

その後、wampまたはApacheを再起動してください。

6

これは私が問題全体を理解するのを助けたものです:

  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(経過時間)、ユーザーID、タイムスタンプ、質問ID、回答ID、正しいとして経過日数、SUM (NOW()、1日間隔)およびuserid = 1

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

4
Kai Noack

symfony using doctrine query builder でこのエラーが発生し、このエラーが orderBy が原因である場合:

selectにしたい列のgroupByに注意を払い、addGroupByの代わりにgroupByを使用してください。

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

で動作する - Symfony3 -

2
Gangai Johann

unique indexgroup_idを追加することができます。 group_idが一意であることが確実な場合.

クエリを修正することなくあなたのケースを解決することができます

遅い回答ですが、回答にはまだ記載されていません。多分それは利用可能なすでに包括的な答えを完成するはずです。少なくとも私があまりにも多くのフィールドでテーブルを分割しなければならなかったとき、それは私のケースを解決した。

2
micaball

正確な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
0
Harry Bosh