6.

Laravel Eloquent select (取得) 完全ガイド

編集
この記事の要点
  • Eloquent の取得: Model::all() / get() / first() / find($id) が基本
  • カラム指定: ->select(["id", "name"]) でメモリ削減
  • 条件 + ソート + 件数: ->where(...)->orderBy(...)->limit(...) でクエリビルダ的に書ける
  • N+1 回避: ->with("posts") による Eager Loading が必須
  • 大量データ: chunk() / cursor() / cursorPaginate() でメモリ枯渇を防ぐ

Eloquent select の基本パターン

Laravel の Eloquent ORM では、クエリビルダと同じメソッドチェーンで SELECT 系の操作を行います。素の SQL を書かずに、PHP のオブジェクトとして結果を扱えるのが最大の利点です。

use App\Models\User;

// 全件取得 (Collection<User>)
$users = User::all();

// 主キーで 1 件
$user = User::find(1);                  // 無ければ null
$user = User::findOrFail(1);            // 無ければ ModelNotFoundException (404)

// 条件付き 1 件
$user = User::where('email', $email)->first();      // 無ければ null
$user = User::where('email', $email)->firstOrFail();// 無ければ例外

// 条件付き複数件
$users = User::where('status', 'active')
            ->orderBy('created_at', 'desc')
            ->limit(20)
            ->get();

// 件数
$count = User::where('status', 'active')->count();

// 存在チェック (count(*) より速い)
if (User::where('email', $email)->exists()) { ... }

取得メソッドの一覧

メソッド戻り値用途
all()Collection全件 (テーブル小さい時のみ)
get()Collectionクエリ結果の全件
first()Model or null1 件目、無ければ null
firstOrFail()Model1 件目、無ければ 404
find($id)Model or null主キー検索
findOrFail($id)Model主キー検索 (例外)
findMany([1,2,3])Collection複数主キーをまとめて
value('name')scalar1 カラムだけ取得
pluck('name')Collection1 カラムを配列状に
count() / sum() / avg()数値集約関数
exists() / doesntExist()bool存在チェック

カラム指定 select

デフォルトでは SELECT * になります。不要なカラムを取らないことでメモリと転送量を削減できます。

// 取得時に指定
$users = User::select(['id', 'name', 'email'])->get();

// 生 SQL の SELECT 句として
$users = User::select(['id', DB::raw('COUNT(*) as cnt')])
            ->groupBy('id')
            ->get();

// addSelect で追加
$users = User::select('id')->addSelect('name')->get();

// $hidden / $visible でモデル側に指定
class User extends Model
{
    protected $hidden = ['password', 'remember_token'];
    // または逆指定
    protected $visible = ['id', 'name', 'email'];
}

where / orderBy / limit / paginate

// 基本
$users = User::where('age', '>=', 20)
            ->where('status', 'active')
            ->orWhere('role', 'admin')
            ->orderBy('created_at', 'desc')
            ->limit(10)
            ->offset(20)
            ->get();

// where のいろいろ
User::whereIn('id', [1, 2, 3])->get();
User::whereNotIn('status', ['banned'])->get();
User::whereBetween('age', [20, 30])->get();
User::whereNull('deleted_at')->get();
User::whereNotNull('email_verified_at')->get();
User::whereDate('created_at', '2026-01-01')->get();
User::whereYear('created_at', 2026)->get();

// クロージャでグループ化
User::where('status', 'active')
    ->where(function ($q) {
        $q->where('role', 'admin')->orWhere('role', 'editor');
    })
    ->get();

// ページング
$users = User::orderBy('id')->paginate(15);     // ?page=2 で取得
$users = User::orderBy('id')->simplePaginate(15); // 件数表示なし、軽量
$users = User::orderBy('id')->cursorPaginate(15); // Seek 方式、大量データ対応

リレーション + Eager Loading (N+1 対策)

Eloquent 最大のハマりどころは N+1 問題です。リレーションを ->with() で事前ロードすることで解決します。

// ❌ N+1: ユーザーごとに posts クエリが発行される
$users = User::all();
foreach ($users as $user) {
    echo $user->posts->count();  // ← 毎回 SELECT
}

// ✅ Eager Loading: 2 クエリで済む
$users = User::with('posts')->get();
foreach ($users as $user) {
    echo $user->posts->count();  // ← 追加クエリなし
}

// ネスト
$users = User::with('posts.comments.user')->get();

// 複数リレーション
$users = User::with(['posts', 'profile', 'roles'])->get();

// リレーションにも条件
$users = User::with(['posts' => function ($q) {
    $q->where('published', true)->orderBy('created_at', 'desc')->limit(5);
}])->get();

// 件数だけ取得 (withCount)
$users = User::withCount('posts')->get();
// → $user->posts_count で参照

whereHas / whereDoesntHave

リレーション先の条件で親レコードを絞り込むパターン:

// 投稿が 5 件以上あるユーザー
$users = User::whereHas('posts', function ($q) {
    $q->where('published', true);
}, '>=', 5)->get();

// 投稿が 1 件もないユーザー
$users = User::whereDoesntHave('posts')->get();

// withWhereHas (Laravel 9+): 条件付き取得 + Eager Load を同時に
$users = User::withWhereHas('posts', function ($q) {
    $q->where('published', true);
})->get();

大量データの取得: chunk / cursor

get()all() はメモリに全件ロードします。10 万件以上なら chunk / cursor を必ず使います。

// chunk: 100 件ずつ取得して処理
User::orderBy('id')->chunk(100, function ($users) {
    foreach ($users as $user) {
        // ...
    }
});

// chunkById: chunk より安全 (更新時に取りこぼし無し)
User::chunkById(100, function ($users) {
    foreach ($users as $user) {
        $user->update(['flag' => 1]);
    }
});

// cursor: 1 件ずつジェネレータで取得 (PHP 側のメモリ最小)
foreach (User::where('active', 1)->cursor() as $user) {
    // 1 件ずつ処理
}

// lazy (Laravel 8+): chunk + cursor のハイブリッド
User::where('active', 1)->lazy(500)->each(function ($user) {
    // ...
});

生 SQL と DB::raw

use Illuminate\Support\Facades\DB;

// 生のカラム式
$users = User::select(DB::raw('COUNT(*) as cnt, role'))
            ->groupBy('role')
            ->get();

// whereRaw
$users = User::whereRaw('YEAR(created_at) = ?', [2026])->get();

// orderByRaw
$users = User::orderByRaw('FIELD(status, ?, ?, ?)', ['admin', 'editor', 'viewer'])->get();

// 完全な生 SQL
$users = DB::select('select * from users where id = ?', [1]);
// 結果は stdClass の配列、Eloquent モデルではない

クエリログでデバッグ

DB::enableQueryLog();
$users = User::with('posts')->where('active', 1)->get();
dd(DB::getQueryLog());

// または toSql() / toRawSql() (Laravel 10.15+)
$sql = User::where('active', 1)->toSql();
// → select * from `users` where `active` = ?

// dd() / dump() でその場で確認
User::where('active', 1)->dd();    // SQL を吐いて die
User::where('active', 1)->dump();  // SQL を吐いて続行

FAQ

Q: all()get() の違い
A: all() は条件なし全件、get() はクエリビルダのチェーンの結果。where()->all() はエラー、where()->get() が正解。

Q: 取得結果を配列にしたい
A: User::all()->toArray() または ->pluck()。素の配列にしたい場合は DB::table('users')->get()->toArray()

Q: Collection と LazyCollection の違いは?
A: 通常の get()Collection (全件メモリ)、cursor() / lazy()LazyCollection (ジェネレータ)。大量データなら必ず後者。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. モデルの作成
  2. $fillable $guarded $hiddenの説明
  3. テーブルの紐づけ
  4. 主キーの指定とインクリメント
  5. タイムスタンプ
  6. モデルでselect
  7. モデルでinsert
  8. モデルでupdate
  9. 現在値に加算する方法
  10. created_at/updated_atの別名指定

最近更新/作成されたページ