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つある

  1. config\database の値をイジる
  2. 直接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を扱う以上、グループにまとめて集計するなんて事よくあります。

そんな時は頻度に応じて【直接書く】【コンフィグいじる】を選べばよさそうですね。

私の作成中のアプリでは頻度が少ないので【直接書く】で行こうと思います。

Concatも直接実行でした。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください