記事ディレクトリ
序文
最近、プロジェクトでは、一部の履歴データを除外しながらデータベース内の重複データをクエリする必要があるため、特定のフィールドでグループ化し、データの一部のフィールドを取り出して表示します。これは、group by ステートメントの使用です。ただし、mysql が上位バージョンの場合、group by を実行する際、選択したフィールドが group by フィールドに属さない場合、SQL ステートメントはエラーを報告します。エラーメッセージは次のとおりです。
1055 - Expression #1 of SELECT list is not in GROUP BY
clause and contains nonaggregated column
'data_export.TrustDataController_store_chain_data_info_method.block_height'
which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by, Time: 0.004000s
問題分析
原則レベル
このエラーは、mysql バージョン 5.7 以降で発生します。mysql
バージョン 5.7 以降のデフォルトの SQL 構成は、sql_mode="ONLY_FULL_GROUP_BY" であり、この構成は厳密に「SQL92 標準」を実装しています。5.6 から 5.7 にアップグレードする場合、ほとんどの場合、プログラムとの互換性を可能な限り保つために、構文の互換性のために sql_mode を 5.6 との一貫性を保つように調整することを選択します。
SQLレベル
SQL の実行時にこの理由は単純です。
選択したフィールドがグループ化に含まれておらず、選択したフィールドが集計関数 (SUM、AVG、MAX、MIN など) を使用していない場合に ONLY_FULL_GROUP_BY が有効になっているためです。 , その後、この SQL クエリは mysql によって不正とみなされ、エラーが報告されます。
認証の問題
- データベースのバージョンを問い合わせる
SELECT VERSION();
サーバー上のデータベースのバージョンは 5.7.36 であると結論付けることができます。
2. sql_mode のステートメントを表示します。
select @@GLOBAL.sql_mode;
クエリ処理の値からわかるように、sql_mode はonly_full_group_by 属性を有効にしています。
解決
方法 1: 関数 ANY_VALUE() を使用してエラー フィールドを含める
any_value() を使用して、クエリする必要がある SQL ステートメントにフィールド名を含めると、結果は通常どおりクエリできます。必要に応じてクエリ フィールドのエイリアスを変更するだけです。
SELECT ANY_VALUE(`block_height`) as block_height, ANY_VALUE(`block_time_stamp`) as block_time_stamp, ANY_VALUE(`tx_hash`) as tx_hash, `_key_ID`,
ANY_VALUE(`_chain_data_ID`) as _chain_data_ID, ANY_VALUE(`_chain_data_index`) as _chain_data_index, ANY_VALUE(`output1`) as output1
FROM `TrustDataController_store_chain_data_info_method`
WHERE (_chain_data_index LIKE "%各地级市数据6d767fc5d458fdb0139d6ad0fe69ec91%") GROUP BY _key_ID ORDER BY ANY_VALUE(`block_time_stamp`) desc
ANY_VALUE() 関数の説明:
MySQL有any_value(field)函数,它主要的作用就是抑制ONLY_FULL_GROUP_BY值被拒绝。
这样sql语句不管是在ONLY_FULL_GROUP_BY模式关闭状态还是在开启模式都可以正常执行,不被mysql拒绝。
any_value()会选择被分到同一组的数据里第一条数据的指定列值作为返回数据。
官方有介绍:https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value
方法 2: SQL ステートメントを使用して sql_mode を一時的に変更する
ONLY_FULL_GROUP_BY を削除し、値をリセットします
SET @@global.sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
上記は、新しく作成されたデータベースに有効なグローバル sql_mode を変更することです。既存のデータベースの場合は、対応するデータベースで実行する必要があります。
SET sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
欠点: mysql データベース サービスを再起動した後も、ONLY_FULL_GROUP_BY が表示されるため、これは一時的なものにすぎません。
方法 3: 構成ファイルを使用して sql_mode を永続的に変更する
Mysqlはサーバー上にインストールされるものとローカルにインストールされるもので、設定ファイルの変更方法が少し異なります。
1. Linux で設定ファイルを変更します。
1) MySQL にログインし、
コマンド mysql -u username -p を使用してログインし、パスワードを入力して SQL を入力します。
show variables like ‘%sql_mode’;
2) my.cnf ファイルを編集します。
ファイル アドレスは通常、/etc/my.cnf、/etc/mysql/my.cnf にあります。vim
コマンドを使用してファイルを編集し、SQL モードの場所を見つけて、ONLY_FULL_GROUP_BY を削除し
、 MySQL を再起動します
。cnf に SQL モードがない可能性があるため、追加する必要があります。
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 サービスを再起動します。
service mysql restart
再起動後、mysql にログインして SQL を入力します: show variables like '%sql_mode'; ONLY_FULL_GROUP_BY がない場合は、成功したことを意味します。そうでない場合は、STRICT_TRANS_TABLES、NO_ENGINE_SUBSTITUTION のみを保持します。追加の内容は次のとおり
です
。
sql-mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
参考記事
MySQL エラー - これは sql_mode=only_full_group_by の完璧なソリューションと互換性がありません