Laravel Query Builder入門!基本構文から実践的なクエリまで徹底解説

1. イントロダクション

Laravelでデータベースを操作する方法として、Eloquent ORMとQuery Builderの2つがあります。Eloquentはオブジェクト指向のアプローチを取り、モデルを通じてデータを操作します。一方で、Query BuilderはSQLに近い記述ができるため、柔軟かつ軽量なクエリの作成に適しています。

EloquentとQuery Builderの違い

特徴Eloquent ORMQuery Builder
記述スタイルオブジェクト指向SQLに近い
可読性高い(Laravelらしい記述)SQLライクで直感的
パフォーマンス比較的遅い(リレーション処理が多い)軽量で高速
使いどころ小〜中規模のデータ処理大量データやカスタムクエリ

Eloquentはリレーションが簡単に扱える一方で、Query Builderはより詳細なクエリを構築できるため、大規模なデータ処理や特定のパフォーマンスチューニングが必要な場合に役立ちます。

Query Builderを使うメリット

  1. SQLに近い記述が可能
    • 生のSQLと似た書き方で、Laravelの便利機能も使える。
  2. Eloquentより軽量
    • 必要最低限の処理でデータを取得できるため、パフォーマンスが向上。
  3. 柔軟なクエリ作成が可能
    • カスタムクエリや複雑なデータ取得を効率的に記述できる。

このように、Query BuilderはEloquentよりも低レベルなデータ操作を可能にしつつ、SQLと同様の直感的な書き方を提供します。

2. Query Builderの基本構文

LaravelのQuery Builderを使うことで、SQLのようなクエリをシンプルに記述できます。このセクションでは、基本的なクエリの書き方を解説します。

2.1 データの取得(SELECT)

データを取得するには DB::table('テーブル名') を使います。

use Illuminate\Support\Facades\DB;

// 全件取得
$users = DB::table('users')->get();

// 1件のみ取得
$user = DB::table('users')->where('id', 1)->first();

カラムを指定して取得

特定のカラムのみ取得する場合は select() を使用します。

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

2.2 条件付き取得(WHERE)

データをフィルタリングするには where() を使います。

// IDが10のユーザーを取得
$user = DB::table('users')->where('id', 10)->first();

// 年齢が20以上のユーザーを取得
$users = DB::table('users')->where('age', '>=', 20)->get();

複数の条件を組み合わせることも可能です。

$users = DB::table('users')
    ->where('age', '>=', 20)
    ->where('status', 'active')
    ->get();

2.3 並び替え(ORDER BY)

データの並び順を指定するには orderBy() を使います。

// 年齢順に昇順ソート
$users = DB::table('users')->orderBy('age', 'asc')->get();

// 名前順に降順ソート
$users = DB::table('users')->orderBy('name', 'desc')->get();

2.4 グループ化(GROUP BY)

特定のカラムごとにデータをグループ化する場合は groupBy() を使用します。

$users = DB::table('users')
    ->select('age', DB::raw('count(*) as total'))
    ->groupBy('age')
    ->get();

2.5 ページネーション(ページ分割)

データをページごとに取得するには paginate() を使います。

$users = DB::table('users')->paginate(10);

これにより、1ページに10件ずつ表示するデータが取得できます。

3. 実践的なクエリの例

ここでは、LaravelのQuery Builderを使って、より実践的なクエリを作成する方法を解説します。テーブルの結合(JOIN)、集計関数、サブクエリ など、実際の開発で役立つテクニックを紹介します。

3.1 テーブルの結合(JOIN)

データベースでは、複数のテーブルを結合して情報を取得することが一般的です。Query Builderでは、join()leftJoin() を使って簡単にテーブルを結合できます。

INNER JOIN(内部結合)

join() を使うと、指定したカラムが一致するデータのみ取得できます。

$orders = DB::table('orders')
    ->join('users', 'orders.user_id', '=', 'users.id')
    ->select('orders.*', 'users.name as user_name')
    ->get();

このクエリは、orders テーブルと users テーブルを user_id で結合し、注文情報とユーザー名を取得します。

LEFT JOIN(外部結合)

leftJoin() を使うと、結合先のテーブルにデータがなくても、元のテーブルのデータは保持されます。

$orders = DB::table('orders')
    ->leftJoin('users', 'orders.user_id', '=', 'users.id')
    ->select('orders.*', 'users.name as user_name')
    ->get();

ユーザー情報がない注文データも取得したい場合は、leftJoin() を使用すると便利です。


3.2 集計関数(COUNT, SUM, AVG など)

Query Builderでは、SQLの集計関数をそのまま利用できます。

件数を取得(COUNT)

特定の条件に合うレコードの件数を取得するには count() を使います。

$userCount = DB::table('users')->count();

合計を計算(SUM)

sum() を使うと、数値の合計値を取得できます。

$totalSales = DB::table('orders')->sum('amount');

平均を取得(AVG)

avg() を使うと、平均値を計算できます。

$averageAge = DB::table('users')->avg('age');

3.3 サブクエリを使ったデータ取得

サブクエリを使うことで、より複雑なデータ取得が可能になります。

最新の注文を取得するサブクエリ

最新の注文を取得するには、サブクエリを selectSub() で使用できます。

$latestOrders = DB::table('users')
    ->select('users.id', 'users.name')
    ->selectSub(function ($query) {
        $query->from('orders')
              ->whereColumn('orders.user_id', 'users.id')
              ->select('created_at')
              ->orderByDesc('created_at')
              ->limit(1);
    }, 'latest_order')
    ->get();

このクエリでは、各ユーザーの最新の注文日時を取得しています。


まとめ

  • JOIN を活用 して複数のテーブルを結合する
  • 集計関数(COUNT、SUM、AVG など) を使って統計情報を取得する
  • サブクエリ を利用して、より高度なデータ取得を行う

4. よくあるミスとエラーの回避方法

LaravelのQuery Builderは便利ですが、間違った使い方をすると意図しない結果になったり、パフォーマンスが悪化したりすることがあります。ここでは、よくあるミスとその対策 を解説します。

4.1 where() の条件ミス

where() を使う際、書き方を間違えると正しくデータが取得できないことがあります。

配列を使った where() のミス

以下のように where() で配列を渡してしまうと、意図した動作になりません。

// ❌ NG: これは動作しない
$users = DB::table('users')->where('id', [1, 2, 3])->get();

この場合、SQLでは id = (1,2,3) のようになってしまい、構文エラーになります。
正しい書き方(whereIn() を使用)

$users = DB::table('users')->whereIn('id', [1, 2, 3])->get();

4.2 join() のデータ重複・NULL値問題

結合したデータの NULL 値に注意

leftJoin() を使うと、結合先のテーブルにデータがない場合、NULLが含まれる可能性があります。

$orders = DB::table('orders')
    ->leftJoin('users', 'orders.user_id', '=', 'users.id')
    ->select('orders.*', 'users.name as user_name')
    ->get();

この場合、users テーブルに該当ユーザーがいない場合、user_nameNULL になります。
NULL 値を考慮した対策

$orders = DB::table('orders')
    ->leftJoin('users', 'orders.user_id', '=', 'users.id')
    ->select('orders.*', DB::raw("COALESCE(users.name, 'ゲスト') as user_name"))
    ->get();

COALESCE() を使うことで、NULL の場合はデフォルト値("ゲスト")を設定できます。


4.3 SQLインジェクションのリスク

Query BuilderはデフォルトでSQLインジェクション対策が施されていますが、生のSQLを使う場合は注意が必要です。

❌ NG: 直接SQLを埋め込む(危険)

$name = $_GET['name']; // ユーザーからの入力
$users = DB::table('users')->whereRaw("name = '$name'")->get();

このコードでは、$name に不正なSQL('; DROP TABLE users; -- など)が入力されると、データベースが破壊される可能性があります。

✅ 正しい書き方(バインディングを使用)

$users = DB::table('users')->whereRaw("name = ?", [$name])->get();

このように ? プレースホルダを使うと、安全にクエリを実行できます。


4.4 N+1 問題と対策

N+1 問題とは?

where() を繰り返し使ってデータを取得すると、無駄なクエリが大量に発生することがあります。

$users = DB::table('users')->get();

foreach ($users as $user) {
    $orders = DB::table('orders')->where('user_id', $user->id)->get();
}

この場合、ユーザーの数だけ orders テーブルにクエリが発行されるため、パフォーマンスが悪化します。

✅ 事前にデータを結合して取得

$users = DB::table('users')
    ->leftJoin('orders', 'users.id', '=', 'orders.user_id')
    ->select('users.*', 'orders.id as order_id', 'orders.amount')
    ->get();

これにより、1回のクエリで必要なデータを取得でき、N+1問題を回避できます。


まとめ

  • whereIn() を正しく使うwhere('id', [1,2,3]) はNG)
  • NULL値を考慮して COALESCE() を使う
  • SQLインジェクション対策として ? を使ったバインディングをする
  • N+1問題を避けるために JOIN を活用する

これらのポイントを押さえておくことで、より安全で効率的なQuery Builderの使い方ができます。

5. まとめ

本記事では、LaravelのQuery Builderの基本的な使い方から、実践的なクエリの記述方法、さらにはよくあるミスの回避方法まで解説しました。

5.1 Query Builderのメリット

Query Builderを使うことで、以下のようなメリットがあります。
SQLに近い記述ができる → 柔軟なクエリを簡単に作成可能
Eloquentより軽量で高速 → 大量データの処理に適している
安全性が確保されている → バインディング機能でSQLインジェクションを防止

一方で、データのリレーションを扱う場合はEloquentの方が便利 なので、適材適所で使い分けるのが重要です。


5.2 EloquentとQuery Builderの使い分け

項目Query BuilderEloquent
記述の簡潔さSQLライクな記述が可能オブジェクト指向で直感的
パフォーマンス軽量で高速モデルを利用するためオーバーヘッドあり
適した用途複雑なクエリ、大量データ処理リレーションを多用する場面

基本的には、シンプルなデータ取得はEloquent、複雑なクエリや大量データの処理にはQuery Builder を使うのがベストです。


5.3 LaravelでSQLを扱うスキルを磨こう!

Query Builderを使いこなすことで、Laravelのデータ操作の幅が大きく広がります。
ぜひ実際の開発で活用しながら、EloquentとQuery Builderを適切に使い分けるスキル を身につけていきましょう!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です