Laravel:GroupByでSQLSTATE[42000]:Syntax error or access violation: 1055発生
Laravel:GroupByしたらエラーが発生
操作性を上げようとGroupByで重複削除しようと画策し組んでみたところエラーが発生。
$productcodes = Productconverter::where('itemcode_id',$item->id)
->groupBy('product_id')
->get();
実行 ⇒ SQLSTATE[42000]:Syntax error or access violation: 1055
調べてみたらEloquantではGroup Byは使えないとの事。
それならと思いクエリビルダで組んでみましたがこれもダメ。
う~ん、どうしたら...と言うことで調べた事をまとめます。
Laravelでgroupbyを使う方法は2つある
- config\database の値をイジる
- 直接SQLを書く
Laravelでは基本的に使えない様にしているようです。
そんな...。
マニュアルを見ると「使いたかったらインジェクション攻撃に注意して直接SQL発行してね」と書いてあります。
なるほど。
config\database の値をイジる
Laravelフォルダの config\database にGroupByを規制している場所があるそうです。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
この中の【'strict' => true】が原因の様で、値を【 false 】に変更します。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
この strict はGroupBy以外にもいろいろ規制しているとの事。
う~ん、よく解らないからこそこういう所いじるのは怖いのです。
と言うことで、GroupByだけ解除する方法は無いか探してみました。
結果、modes を追加して許可するものを決めれるらしい。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'strict' => true,
'modes' => [
// 'ONLY_FULL_GROUP_BY',
'STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_ENGINE_SUBSTITUTION',
],
'engine' => null,
],
えっ、それもレベル高いです...。
他のエラーが生じた時、ココが原因となっても嫌なので、素直にマニュアルに従う事にしました。
直接SQLを書く
直接書く事で「インジェクション攻撃が...」とはなりますが、まぁそんなに直接書くパートがある訳じゃないので。
$productcodes = Productconverter::where('itemcode_id',$item->id)
->selectRaw('product_id')
->groupBy('product_id')
->get();
うん、狙い通りに動いてます。
まとめ
DBを扱う以上、グループにまとめて集計するなんて事よくあります。
そんな時は頻度に応じて【直接書く】【コンフィグいじる】を選べばよさそうですね。
私の作成中のアプリでは頻度が少ないので【直接書く】で行こうと思います。


