この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:7
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: SELECT
SEOタイトル: Laravel Query Builder の SELECT 完全ガイド

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>基本: <code>DB::table('users')->select('name', 'email')->get()</code></li><li>生 SQL は <code>selectRaw()</code>、重複排除は <code>distinct()</code>、列追加は <code>addSelect()</code></li><li>取得は <code>get() / first() / find() / value() / pluck()</code> を場面で使い分け</li><li>JOIN / GROUP BY / HAVING / サブクエリ <code>selectSub()</code> もチェーンで書ける</li><li>Eloquent でも同じ感覚で <code>User::select('name')->where(...)->get()</code></li></ul></td></tr></table>
<h2>基本: select() で列を指定</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">use Illuminate\Support\Facades\DB;

// 全列
$users = DB::table(&apos;users&apos;)->get();

// 列指定
$users = DB::table(&apos;users&apos;)->select(&apos;id&apos;, &apos;name&apos;, &apos;email&apos;)->get();

// エイリアス
$users = DB::table(&apos;users&apos;)
    ->select(&apos;id&apos;, &apos;name AS user_name&apos;, &apos;email&apos;)
    ->get();

// 配列で渡す
$users = DB::table(&apos;users&apos;)->select([&apos;id&apos;, &apos;name&apos;])->get();</code></pre>
<h2>selectRaw: 生 SQL 式</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// COUNT / SUM 等の集計
$stats = DB::table(&apos;orders&apos;)
    ->selectRaw(&apos;user_id, COUNT(*) AS cnt, SUM(amount) AS total&apos;)
    ->groupBy(&apos;user_id&apos;)
    ->get();

// 日付フォーマット
$logs = DB::table(&apos;access_logs&apos;)
    ->selectRaw("DATE_FORMAT(created_at, &apos;%Y-%m-%d&apos;) AS day, COUNT(*) AS hits")
    ->groupBy(&apos;day&apos;)
    ->get();

// バインドパラメータを使う(SQL インジェクション対策)
$users = DB::table(&apos;users&apos;)
    ->selectRaw(&apos;price * ? AS price_with_tax&apos;, [1.1])
    ->get();</code></pre>
<h2>addSelect: 列を追加</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$query = DB::table(&apos;users&apos;)->select(&apos;id&apos;, &apos;name&apos;);

if ($request->include_email) {
    $query->addSelect(&apos;email&apos;);
}

if ($request->include_role) {
    $query->addSelect(&apos;role&apos;);
}

$users = $query->get();</code></pre>
<h2>distinct: 重複排除</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ユニークな国一覧
$countries = DB::table(&apos;users&apos;)
    ->select(&apos;country&apos;)
    ->distinct()
    ->get();

// 複数列の組み合わせで distinct
$pairs = DB::table(&apos;orders&apos;)
    ->select(&apos;user_id&apos;, &apos;product_id&apos;)
    ->distinct()
    ->get();</code></pre>
<h2>WHERE / ORDER BY / GROUP BY / HAVING</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$users = DB::table(&apos;users&apos;)
    ->select(&apos;id&apos;, &apos;name&apos;, &apos;created_at&apos;)
    ->where(&apos;active&apos;, 1)
    ->where(&apos;age&apos;, &apos;>=&apos;, 18)
    ->whereIn(&apos;country&apos;, [&apos;JP&apos;, &apos;US&apos;, &apos;KR&apos;])
    ->whereNull(&apos;deleted_at&apos;)
    ->whereBetween(&apos;age&apos;, [20, 65])
    ->orderBy(&apos;created_at&apos;, &apos;desc&apos;)
    ->get();

// GROUP BY / HAVING
$summary = DB::table(&apos;orders&apos;)
    ->select(&apos;user_id&apos;, DB::raw(&apos;SUM(amount) AS total&apos;))
    ->groupBy(&apos;user_id&apos;)
    ->having(&apos;total&apos;, &apos;>&apos;, 10000)
    ->orderByDesc(&apos;total&apos;)
    ->get();</code></pre>
<h2>JOIN を組み合わせた SELECT</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$rows = DB::table(&apos;users&apos;)
    ->join(&apos;orders&apos;, &apos;users.id&apos;, &apos;=&apos;, &apos;orders.user_id&apos;)
    ->leftJoin(&apos;payments&apos;, &apos;orders.id&apos;, &apos;=&apos;, &apos;payments.order_id&apos;)
    ->select(
        &apos;users.id&apos;,
        &apos;users.name&apos;,
        &apos;orders.id AS order_id&apos;,
        &apos;orders.amount&apos;,
        &apos;payments.paid_at&apos;
    )
    ->where(&apos;orders.status&apos;, &apos;completed&apos;)
    ->orderBy(&apos;orders.created_at&apos;, &apos;desc&apos;)
    ->get();</code></pre>
<h2>サブクエリ: selectSub / whereExists</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// selectSub: 各 user に最終ログイン時刻を付与
$users = DB::table(&apos;users&apos;)
    ->select(&apos;id&apos;, &apos;name&apos;)
    ->selectSub(function ($q) {
        $q->select(&apos;created_at&apos;)
          ->from(&apos;login_logs&apos;)
          ->whereColumn(&apos;login_logs.user_id&apos;, &apos;users.id&apos;)
          ->orderByDesc(&apos;created_at&apos;)
          ->limit(1);
    }, &apos;last_login_at&apos;)
    ->get();

// whereExists: 注文を持つユーザー
$users = DB::table(&apos;users&apos;)
    ->whereExists(function ($q) {
        $q->select(DB::raw(1))
          ->from(&apos;orders&apos;)
          ->whereColumn(&apos;orders.user_id&apos;, &apos;users.id&apos;);
    })
    ->get();</code></pre>
<h2>取得メソッドの使い分け</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>メソッド</th><th>返り値</th><th>用途</th></tr></thead>
<tbody>
<tr><td><code>get()</code></td><td>Collection of stdClass</td><td>複数行取得</td></tr>
<tr><td><code>first()</code></td><td>stdClass / null</td><td>1 行目を取得</td></tr>
<tr><td><code>find($id)</code></td><td>stdClass / null</td><td>PK で 1 件</td></tr>
<tr><td><code>value('column')</code></td><td>scalar</td><td>1 列だけ取得</td></tr>
<tr><td><code>pluck('name')</code></td><td>Collection<string></td><td>単一列をリスト化</td></tr>
<tr><td><code>pluck('name', 'id')</code></td><td>Collection<id => name></td><td>キー付きリスト</td></tr>
<tr><td><code>count()</code></td><td>int</td><td>行数</td></tr>
<tr><td><code>exists()</code></td><td>bool</td><td>存在チェック(高速)</td></tr>
<tr><td><code>chunk(100, fn)</code></td><td>void</td><td>大量データ分割処理</td></tr>
<tr><td><code>cursor()</code></td><td>Generator</td><td>1 行ずつメモリ節約</td></tr>
</tbody>
</table>

<h2>pluck の便利な使い方</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// id だけのリスト
$ids = DB::table(&apos;users&apos;)->where(&apos;active&apos;, 1)->pluck(&apos;id&apos;)->all();
// [1, 2, 3, 5, 8]

// id => name の連想配列(HTML select 用)
$options = DB::table(&apos;users&apos;)->pluck(&apos;name&apos;, &apos;id&apos;);
// [1 => &apos;Taro&apos;, 2 => &apos;Hanako&apos;, ...]

// Blade で
// <select>
//   @foreach ($options as $id => $name)
//     <option value="{{ $id }}">{{ $name }}</option>
//   @endforeach
// </select></code></pre>
<h2>ページネーション</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$users = DB::table(&apos;users&apos;)
    ->select(&apos;id&apos;, &apos;name&apos;)
    ->orderBy(&apos;id&apos;)
    ->paginate(20);   // 1ページ20件

// Blade
// {{ $users->links() }}

// simplePaginate は総件数を計算せず軽量
$users = DB::table(&apos;users&apos;)->simplePaginate(20);

// カーソルベース(大量データ向け)
$users = DB::table(&apos;users&apos;)->orderBy(&apos;id&apos;)->cursorPaginate(20);</code></pre>
<h2>Eloquent でも同じ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">use App\Models\User;

// 全列
$users = User::all();

// 列指定
$users = User::select(&apos;id&apos;, &apos;name&apos;, &apos;email&apos;)->where(&apos;active&apos;, 1)->get();

// リレーションも eager load しつつ
$users = User::with(&apos;orders:id,user_id,amount&apos;)
    ->select(&apos;id&apos;, &apos;name&apos;)
    ->get();

// pluck
$emails = User::where(&apos;active&apos;, 1)->pluck(&apos;email&apos;);</code></pre>
<h2>パフォーマンスのコツ</h2>

<ul>
<li><strong>必要な列だけ select</strong>: TEXT / JSON 列を含む全列取得は重い</li>
<li><strong>EXPLAIN で確認</strong>: <code>DB::table(...)->toSql()</code> でクエリ確認 → MySQL で EXPLAIN</li>
<li><strong>N+1 回避</strong>: Eloquent では <code>with()</code> で eager load</li>
<li><strong>chunk / cursor</strong>: 10 万行以上扱うときは <code>chunk(1000)</code> or <code>cursor()</code></li>
<li><strong>インデックス</strong>: where / orderBy 列に index、複合 index は左端から</li>
<li><strong>QueryBuilder の <code>toSql()</code> + DB::listen() でロガー</strong></li>
</ul>

<h2>FAQ</h2>

<p><strong>Q: get() と first() の違い</strong><br />
A: get() は Collection(複数行)、first() は最初の 1 行のオブジェクト or null。「絶対1件しかないクエリ」でも get() を呼ぶと配列処理が必要になり面倒。</p>

<p><strong>Q: 実行された SQL を確認したい</strong><br />
A: <code>DB::table(...)->toSql()</code> でクエリ文字列、<code>DB::table(...)->dd()</code> でバインド込みダンプ。<code>DB::listen(fn($q) => Log::info($q->sql))</code> で全クエリログ。</p>

<p><strong>Q: select で alias を付けると Eloquent で取れない</strong><br />
A: モデル属性として取得するには <code>$user->getAttribute('alias')</code> or <code>$user->alias</code>。生クエリの結果は stdClass なので注意。</p>