エンジニアの卵の成長日記

ふわっちで配信してますhttps://whowatch.tv/profile/w:kurowasi2525

Laravel+PostgreSQLでの異なる型のINNER JOINの方法

Laravelはデータベースクレリビルダってのがある

データベースクエリビルダはスラスラと書ける(fluent)便利なインターフェイスで、クエリを作成し実行するために使用します。アプリケーションで行われるほとんどのデーターベース操作が可能で、サポートしている全データベースシステムに対し使用できます。

こいつのおかげでSQL文を書かなくて済む

SELECT文とかもこんな感じで書ける

$users = DB::table('users')->select('name', 'email as user_email')->get();

今回問題のINNER JOIN文もこんな感じでかける

$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();

今回ぶち当たった壁は違う型でのINNER JOINする方法

上記の例の場合、usersテーブルのidがint8・contactsテーブルのuser_idがvarcharの場合、

型が違うためjoinできない

CASTすればよいと思い、試してみた

$users = DB::table('users')
            ->join('contacts', 'users.id', '=', 'contacts.user_id::int')
            ->get();

contacts.user_id::intなんて存在しないよって怒られる

原因は多分これみたい

LaravelクエリビルダはアプリケーションをSQLインジェクション攻撃から守るために、PDOパラメーターによるバインディングを使用します。バインドする文字列をクリーンにしてから渡す必要はありません。

解決方法はDB::raw()メソッド

たまにクエリの中でSQLを直接使用したいことがあります。このようなSQLでは文字をそのまま埋め込むだけですので、SQLインジェクションをされないように気をつけてください! エスケープなしのSQLを使用する場合はDB::rawメソッドを使用します。

こんな感じにすれば完了

$users = DB::table('users')
            ->join('contacts', 'users.id', '=', DB::raw('contacts.user_id::int'))
            ->get();


参考サイト
データベース:クエリビルダ 5.3 Laravel