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

2019/10/12

2017/09/26投稿ではてなブログから移行した内容です.

データベースクエリビルダ

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する方法

今回ぶち当たった壁は違う型での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

Togelloというサービスをリリースいたしました。