MySQL
エラー1055:ONLY_FULL_GROUP_BY:何かがGROUP BY句にない...
サーチ…
前書き
GROUP BY
拡張機能をGROUP BY
しようと努力しています。少なくとも、クエリ作成者がそれを焼くのが難しくなっています。
備考
長い間、MySQLにはGROUP BY
に対する非標準的な拡張が含まれていました。これは効率の名目で奇妙な動作を可能にします。この拡張により、世界中の無数の開発者が、何をしているのかを完全に理解することなく、実動コードでGROUP BY
を使用することができました。
特に、標準のGROUP BY
句で列を列挙する必要があるため、 GROUP BY
問合せでSELECT *
を使用することは好ましくありません。残念なことに、多くの開発者がこれを行っています。
これを読む。 https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
MySQLチームは、生産コードを乱すことなくこの誤った機能を修正しようとしています。彼らは追加sql_mode
命名5.7.5にフラグをONLY_FULL_GROUP_BY
標準の動作を強要します。最近のリリースでは、デフォルトでフラグをオンにしていました。ローカルMySQLを5.7.14にアップグレードすると、フラグがオンになり、以前の拡張機能に依存するプロダクションコードが機能しなくなりました。
最近1055のエラーが発生した場合、どのような選択ができますか?
- 問題のSQLクエリを修正するか、作成者にその旨を伝えることができます。
- 使用しているアプリケーションソフトウェアと互換性のあるMySQL互換のバージョンにロールバックしてください。
- サーバーの
sql_mode
を変更して、新しく設定されたONLY_FULL_GROUP_BY
モードをONLY_FULL_GROUP_BY
ます。
SET
コマンドを実行すると、モードを変更できます。
SET 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に接続した直後にそれを行うなら、このトリックを行うべきです。
それとも、あなたは見つけることができますMySQLのインストール中に初期化ファイルを 、見つけsql_mode=
行をし、省略し、それを変更ONLY_FULL_GROUP_BY
、そしてサーバーを再起動してください。
GROUP BYの使用と誤用
SELECT item.item_id, item.name, /* not SQL-92 */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
item
と呼ばれるテーブルに行が表示され、 uses
というテーブルに関連する行の数が表示されuses
。これは正常に動作しますが、残念ながら標準のSQL-92ではありません。
何故なの? GROUP BY
問合せのSELECT
句(およびORDER BY
句)には、次のような列が含まれている必要があるためです。
-
GROUP BY
句に記載されている -
COUNT()
、MIN()
などの集合関数。
この例のSELECT
句には、いずれかの条件を満たす列ではないitem.name
ています。 MySQL 5.6以前では、SQLモードにONLY_FULL_GROUP_BY
が含まれている場合、このクエリは拒否されONLY_FULL_GROUP_BY
。
この例のクエリは、このようにGROUP BY
句を変更することによってSQL-92標準に準拠するようにすることができます。
SELECT item.item_id, item.name,
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id, item.name
後のSQL-99標準では、DBMSがグループキー列との間の機能的依存関係を証明できる場合、 SELECT
文で集約されていない列をグループキーから省略することができます。のでitem.name
上の機能的に依存しているitem.item_id
、最初の例では、有効なSQL-99です。 MySQLはバージョン5.7で機能依存プローバを取得しました。元の例は、 ONLY_FULL_GROUP_BY
下でONLY_FULL_GROUP_BY
ます。
GROUP BYを誤って予測できない結果を返す:Murphy's Law
SELECT item.item_id, uses.category, /* nonstandard */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
itemと呼ばれるテーブルに行が表示され、usesというテーブルに関連する行の数が表示されます。また、 uses.category
という列の値も表示されuses.category
。
このクエリは、 ONLY_FULL_GROUP_BY
フラグが現れる前にMySQLで動作します。これは、 MySQLの非標準的な拡張機能をGROUP BY
に使用します 。
しかし、問合せには問題があります。 uses
表の複数の行がJOIN
句のON
条件と一致すると、MySQLはその列の1つからcategory
列を戻します。どの列?クエリの作成者とアプリケーションのユーザーは、事前にそのことを知ることはできません。形式的に言えば、 予測できないことです.MySQLは必要な値を返すことができます。
予測不能とは、 ランダムなものと同様ですが、大きな違いが1つあります。 ランダムな選択が時々変わると予想されるかもしれません。したがって、選択肢がランダムであった場合、デバッグまたはテスト中にその選択肢を検出する可能性があります。 予期しない結果がより悪化します。MySQLはクエリを使用するたびに同じ結果を返します。時には、それは別の結果を引き起こすMySQLサーバの新しいバージョンです。ときには問題を引き起こすテーブルが増えています。間違って行くことができます、間違って行くと、あなたがそれを期待していないとき。それはマーフィーの法則です。
MySQLチームは、開発者がこの間違いを犯すのをより困難にするよう努めてきました。 5.7シーケンスの新しいバージョンのMySQLには、 sql_mode
というsql_mode
フラグがONLY_FULL_GROUP_BY
ます。このフラグが設定されると、MySQLサーバは1055エラーを返し、この種のクエリの実行を拒否します。
SELECT *を使用してGROUP BYを誤解し、それを修正する方法。
時には、 SELECT
句に*
を付けて照会すると、このようになります。
SELECT item.*, /* nonstandard */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
このようなクエリは、 ONLY_FULL_GROUP_BY
標準に準拠するようにリファクタリングする必要があります。
これを行うには、 item_id
number_of_uses
値を正しく返すためにGROUP BY
正しく使用するサブクエリが必要item_id
。このサブクエリは、 uses
テーブルを調べるだけで済み、短くて甘いです。
SELECT item_id, COUNT(*) number_of_uses
FROM uses
GROUP BY item_id
次に、そのサブクエリをitem
テーブルと結合することができます。
SELECT item.*, usecount.number_of_uses
FROM item
JOIN (
SELECT item_id, COUNT(*) number_of_uses
FROM uses
GROUP BY item_id
) usecount ON item.item_id = usecount.item_id
これにより、 GROUP BY
句を単純で正確にすることができます。また、 *
指定子を使用することもできます。
注意:それにもかかわらず、賢明な開発者はいずれの場合でも*
指定子の使用を避けます。クエリに必要な列を一覧表示する方が一般的です。
ANY_VALUE()
SELECT item.item_id, ANY_VALUE(uses.tag) tag,
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
item
というテーブルの行、関連する行の数、およびuses
という関連テーブルの値の1つを表示します。
このANY_VALUE()
関数は、奇妙な一種の集合関数と考えることができます。 count、sum、またはmaximumを返す代わりに、MySQLサーバに、問題のグループから1つの値を任意に選択するように指示します。エラー1055を回避する方法です。
プロダクションアプリケーションのクエリでANY_VALUE()
を使用する場合は注意が必要です。
それは本当にSURPRISE_ME()
と呼ばれるべきです。 GROUP BYグループの一部の行の値を返します。それが返す行は不確定です。つまり、それはMySQLサーバーまでです。正式には、予測不可能な値を返します。
サーバーはランダムな値を選択しません。それよりも悪いです。クエリが実行されるたびに同じ値が返されます。テーブルが大きくなったり小さくなったり、サーバのRAMが多かったり、サーバのバージョンが変わったり、逆に(逆に)何かがあったとしても、まったく理由なしに変更することができます。
あなたは警告されています。