はじめに

Laravelのデータベースクエリビルダーは、データベースクエリを作成し実行するための便利で流暢なインターフェースを提供します。これは、アプリケーション内のほとんどのデータベース操作を実行するために使用でき、Laravelがサポートするすべてのデータベースシステムと完全に連携します。

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

PDOはカラム名のバインディングをサポートしていません。したがって、ユーザー入力がクエリで参照されるカラム名を決定することを決して許可しないでください。これには「order by」カラムも含まれます。

データベースクエリの実行

テーブルからすべての行を取得する

  1. ``````php
  2. <?php
  3. namespace App\Http\Controllers;
  4. use Illuminate\Support\Facades\DB;
  5. use Illuminate\View\View;
  6. class UserController extends Controller
  7. {
  8. /**
  9. * Show a list of all of the application's users.
  10. */
  11. public function index(): View
  12. {
  13. $users = DB::table('users')->get();
  14. return view('user.index', ['users' => $users]);
  15. }
  16. }
  17. `
  1. ``````php
  2. use Illuminate\Support\Facades\DB;
  3. $users = DB::table('users')->get();
  4. foreach ($users as $user) {
  5. echo $user->name;
  6. }
  7. `

Laravelコレクションは、データをマッピングおよび削減するための非常に強力なメソッドを提供します。Laravelコレクションに関する詳細は、コレクションのドキュメントを参照してください。

テーブルから単一の行/カラムを取得する

データベーステーブルから単一の行を取得するだけが必要な場合は、DBファサードのfirstメソッドを使用できます。このメソッドは、単一のstdClassオブジェクトを返します:

  1. $user = DB::table('users')->where('name', 'John')->first();
  2. return $user->email;

データベーステーブルから単一の行を取得したいが、一致する行が見つからない場合はIlluminate\Database\RecordNotFoundExceptionをスローしたい場合は、firstOrFailメソッドを使用できます。RecordNotFoundExceptionがキャッチされない場合、404 HTTPレスポンスが自動的にクライアントに返されます:

  1. $user = DB::table('users')->where('name', 'John')->firstOrFail();

行全体が必要ない場合は、valueメソッドを使用してレコードから単一の値を抽出できます。このメソッドは、カラムの値を直接返します:

  1. $email = DB::table('users')->where('name', 'John')->value('email');
  1. ``````php
  2. $user = DB::table('users')->find(3);
  3. `

カラム値のリストを取得する

単一のカラムの値を含むIlluminate\Support\Collectionインスタンスを取得したい場合は、pluckメソッドを使用できます。この例では、ユーザーのタイトルのコレクションを取得します:

  1. use Illuminate\Support\Facades\DB;
  2. $titles = DB::table('users')->pluck('title');
  3. foreach ($titles as $title) {
  4. echo $title;
  5. }

結果のコレクションが使用するカラムを指定するには、pluckメソッドに2番目の引数を提供します:

  1. $titles = DB::table('users')->pluck('title', 'name');
  2. foreach ($titles as $name => $title) {
  3. echo $title;
  4. }

結果のチャンク処理

数千のデータベースレコードを操作する必要がある場合は、chunkメソッドを使用することを検討してください。DBファサードが提供するこのメソッドは、結果の小さなチャンクを一度に取得し、各チャンクを処理のためにクロージャに渡します。たとえば、usersテーブル全体を100レコードずつチャンクで取得します:

  1. use Illuminate\Support\Collection;
  2. use Illuminate\Support\Facades\DB;
  3. DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
  4. foreach ($users as $user) {
  5. // ...
  6. }
  7. });

クロージャからfalseを返すことで、さらなるチャンクの処理を停止できます:

  1. DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
  2. // Process the records...
  3. return false;
  4. });

結果をチャンク処理しながらデータベースレコードを更新している場合、チャンク結果が予期しない方法で変わる可能性があります。チャンク処理中に取得したレコードを更新する予定がある場合は、chunkByIdメソッドを使用するのが最善です。このメソッドは、レコードの主キーに基づいて結果を自動的にページネートします:

  1. DB::table('users')->where('active', false)
  2. ->chunkById(100, function (Collection $users) {
  3. foreach ($users as $user) {
  4. DB::table('users')
  5. ->where('id', $user->id)
  6. ->update(['active' => true]);
  7. }
  8. });

チャンクコールバック内でレコードを更新または削除する場合、主キーまたは外部キーの変更がチャンククエリに影響を与える可能性があります。これにより、レコードがチャンク結果に含まれない可能性があります。

遅延ストリーミング結果

  1. ``````php
  2. use Illuminate\Support\Facades\DB;
  3. DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
  4. // ...
  5. });
  6. `

再度、取得したレコードを反復処理しながら更新する予定がある場合は、lazyByIdまたはlazyByIdDescメソッドを使用するのが最善です。これらのメソッドは、レコードの主キーに基づいて結果を自動的にページネートします:

  1. DB::table('users')->where('active', false)
  2. ->lazyById()->each(function (object $user) {
  3. DB::table('users')
  4. ->where('id', $user->id)
  5. ->update(['active' => true]);
  6. });

反復処理中にレコードを更新または削除する場合、主キーまたは外部キーの変更がチャンククエリに影響を与える可能性があります。これにより、結果にレコードが含まれない可能性があります。

集計

クエリビルダーは、countmaxminavg、およびsumのような集計値を取得するためのさまざまなメソッドも提供します。クエリを構築した後に、これらのメソッドのいずれかを呼び出すことができます:

  1. use Illuminate\Support\Facades\DB;
  2. $users = DB::table('users')->count();
  3. $price = DB::table('orders')->max('price');

もちろん、これらのメソッドを他の句と組み合わせて、集計値の計算方法を微調整することもできます:

  1. $price = DB::table('orders')
  2. ->where('finalized', 1)
  3. ->avg('price');

レコードの存在を確認する

クエリの制約に一致するレコードが存在するかどうかを確認するために、countメソッドを使用する代わりに、existsおよびdoesntExistメソッドを使用できます:

  1. if (DB::table('orders')->where('finalized', 1)->exists()) {
  2. // ...
  3. }
  4. if (DB::table('orders')->where('finalized', 1)->doesntExist()) {
  5. // ...
  6. }

選択文

選択句の指定

データベーステーブルからすべてのカラムを選択したいわけではないかもしれません。selectメソッドを使用して、クエリのカスタム「select」句を指定できます:

  1. use Illuminate\Support\Facades\DB;
  2. $users = DB::table('users')
  3. ->select('name', 'email as user_email')
  4. ->get();
  1. ``````php
  2. $users = DB::table('users')->distinct()->get();
  3. `

すでにクエリビルダーインスタンスがあり、既存の選択句にカラムを追加したい場合は、addSelectメソッドを使用できます:

  1. $query = DB::table('users')->select('name');
  2. $users = $query->addSelect('age')->get();

生の式

時には、クエリに任意の文字列を挿入する必要があるかもしれません。生の文字列式を作成するには、rawメソッドを使用します。DBファサードが提供します:

  1. $users = DB::table('users')
  2. ->select(DB::raw('count(*) as user_count, status'))
  3. ->where('status', '<>', 1)
  4. ->groupBy('status')
  5. ->get();

生のステートメントは文字列としてクエリに注入されるため、SQLインジェクションの脆弱性を作成しないように非常に注意する必要があります。

生のメソッド

  1. <a name="selectraw"></a>
  2. #### selectRaw
  3. `````selectRaw`````メソッドは、`````addSelect(DB::raw(/* ... */))`````の代わりに使用できます。このメソッドは、オプションのバインディング配列を第2引数として受け取ります:
  4. ``````php
  5. $orders = DB::table('orders')
  6. ->selectRaw('price * ? as price_with_tax', [1.0825])
  7. ->get();
  8. `

whereRaw / orWhereRaw

  1. ``````php
  2. $orders = DB::table('orders')
  3. ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
  4. ->get();
  5. `

havingRaw / orHavingRaw

  1. ``````php
  2. $orders = DB::table('orders')
  3. ->select('department', DB::raw('SUM(price) as total_sales'))
  4. ->groupBy('department')
  5. ->havingRaw('SUM(price) > ?', [2500])
  6. ->get();
  7. `

orderByRaw

orderByRawメソッドを使用して、「order by」句の値として生の文字列を提供できます:

  1. $orders = DB::table('orders')
  2. ->orderByRaw('updated_at - created_at DESC')
  3. ->get();

groupByRaw

groupByRawメソッドを使用して、group by句の値として生の文字列を提供できます:

  1. $orders = DB::table('orders')
  2. ->select('city', 'state')
  3. ->groupByRaw('city, state')
  4. ->get();

結合

内部結合句

クエリビルダーは、クエリに結合句を追加するためにも使用できます。基本的な「内部結合」を実行するには、クエリビルダーインスタンスでjoinメソッドを使用します。joinメソッドに渡される最初の引数は、結合する必要があるテーブルの名前であり、残りの引数は結合のカラム制約を指定します。単一のクエリで複数のテーブルを結合することもできます:

  1. use Illuminate\Support\Facades\DB;
  2. $users = DB::table('users')
  3. ->join('contacts', 'users.id', '=', 'contacts.user_id')
  4. ->join('orders', 'users.id', '=', 'orders.user_id')
  5. ->select('users.*', 'contacts.phone', 'orders.price')
  6. ->get();

左結合 / 右結合句

「内部結合」の代わりに「左結合」または「右結合」を実行したい場合は、leftJoinまたはrightJoinメソッドを使用します。これらのメソッドは、joinメソッドと同じシグネチャを持っています:

  1. $users = DB::table('users')
  2. ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
  3. ->get();
  4. $users = DB::table('users')
  5. ->rightJoin('posts', 'users.id', '=', 'posts.user_id')
  6. ->get();

クロス結合句

  1. ``````php
  2. $sizes = DB::table('sizes')
  3. ->crossJoin('colors')
  4. ->get();
  5. `

高度な結合句

より高度な結合句を指定することもできます。開始するには、joinメソッドの第2引数としてクロージャを渡します。クロージャは、Illuminate\Database\Query\JoinClauseインスタンスを受け取り、「join」句に対する制約を指定できます:

  1. DB::table('users')
  2. ->join('contacts', function (JoinClause $join) {
  3. $join->on('users.id', '=', 'contacts.user_id')->orOn(/* ... */);
  4. })
  5. ->get();

結合に「where」句を使用したい場合は、whereおよびorWhereメソッドをJoinClauseインスタンスが提供します。これらのメソッドは、2つのカラムを比較するのではなく、カラムを値と比較します:

  1. DB::table('users')
  2. ->join('contacts', function (JoinClause $join) {
  3. $join->on('users.id', '=', 'contacts.user_id')
  4. ->where('contacts.user_id', '>', 5);
  5. })
  6. ->get();

サブクエリ結合

  1. ``````php
  2. $latestPosts = DB::table('posts')
  3. ->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
  4. ->where('is_published', true)
  5. ->groupBy('user_id');
  6. $users = DB::table('users')
  7. ->joinSub($latestPosts, 'latest_posts', function (JoinClause $join) {
  8. $join->on('users.id', '=', 'latest_posts.user_id');
  9. })->get();
  10. `

ラテラル結合

ラテラル結合は、PostgreSQL、MySQL >= 8.0.14、およびSQL Serverで現在サポートされています。

  1. この例では、ユーザーのコレクションと、ユーザーの最近の3つのブログ投稿を取得します。各ユーザーは、結果セット内で最大3行を生成できます:それぞれの最近のブログ投稿のために。結合条件は、現在のユーザー行を参照する`````whereColumn`````句内で指定されます:
  2. ``````php
  3. $latestPosts = DB::table('posts')
  4. ->select('id as post_id', 'title as post_title', 'created_at as post_created_at')
  5. ->whereColumn('user_id', 'users.id')
  6. ->orderBy('created_at', 'desc')
  7. ->limit(3);
  8. $users = DB::table('users')
  9. ->joinLateral($latestPosts, 'latest_posts')
  10. ->get();
  11. `

ユニオン

クエリビルダーは、2つ以上のクエリを「ユニオン」するための便利なメソッドも提供します。たとえば、最初のクエリを作成し、unionメソッドを使用して他のクエリとユニオンできます:

  1. use Illuminate\Support\Facades\DB;
  2. $first = DB::table('users')
  3. ->whereNull('first_name');
  4. $users = DB::table('users')
  5. ->whereNull('last_name')
  6. ->union($first)
  7. ->get();
  1. <a name="basic-where-clauses"></a>
  2. ## 基本的なwhere句
  3. <a name="where-clauses"></a>
  4. ### where句
  5. クエリビルダーの`````where`````メソッドを使用して、「where」句をクエリに追加できます。`````where`````メソッドへの最も基本的な呼び出しには、3つの引数が必要です。最初の引数はカラムの名前です。2番目の引数は演算子で、データベースがサポートする任意の演算子を使用できます。3番目の引数は、カラムの値と比較する値です。
  6. たとえば、次のクエリは、`````votes`````カラムの値が`````100`````に等しく、`````age`````カラムの値が`````35`````より大きいユーザーを取得します:
  7. ``````php
  8. $users = DB::table('users')
  9. ->where('votes', '=', 100)
  10. ->where('age', '>', 35)
  11. ->get();
  12. `

便利なことに、カラムが=に対して指定された値であることを確認したい場合は、whereメソッドに値を第2引数として渡すことができます。Laravelは、=演算子を使用したいと仮定します:

  1. $users = DB::table('users')->where('votes', 100)->get();

前述のように、データベースシステムがサポートする任意の演算子を使用できます:

  1. $users = DB::table('users')
  2. ->where('votes', '>=', 100)
  3. ->get();
  4. $users = DB::table('users')
  5. ->where('votes', '<>', 100)
  6. ->get();
  7. $users = DB::table('users')
  8. ->where('name', 'like', 'T%')
  9. ->get();
  1. ``````php
  2. $users = DB::table('users')->where([
  3. ['status', '=', '1'],
  4. ['subscribed', '<>', '1'],
  5. ])->get();
  6. `

PDOはカラム名のバインディングをサポートしていません。したがって、ユーザー入力がクエリで参照されるカラム名を決定することを決して許可しないでください。「order by」カラムも含まれます。

Or Where句

クエリビルダーのwhereメソッドへの呼び出しを連鎖させると、「where」句はand演算子を使用して結合されます。ただし、orWhereメソッドを使用して、or演算子を使用してクエリに句を結合することができます。orWhereメソッドは、whereメソッドと同じ引数を受け取ります:

  1. $users = DB::table('users')
  2. ->where('votes', '>', 100)
  3. ->orWhere('name', 'John')
  4. ->get();

「or」条件を括弧内にグループ化する必要がある場合は、orWhereメソッドに最初の引数としてクロージャを渡すことができます:

  1. $users = DB::table('users')
  2. ->where('votes', '>', 100)
  3. ->orWhere(function (Builder $query) {
  4. $query->where('name', 'Abigail')
  5. ->where('votes', '>', 50);
  6. })
  7. ->get();

上記の例は、次のSQLを生成します:

  1. select * from users where votes > 100 or (name = 'Abigail' and votes > 50)

グローバルスコープが適用されるときに予期しない動作を避けるために、orWhere呼び出しを常にグループ化する必要があります。

Where Not句

  1. ``````php
  2. $products = DB::table('products')
  3. ->whereNot(function (Builder $query) {
  4. $query->where('clearance', true)
  5. ->orWhere('price', '<', 10);
  6. })
  7. ->get();
  8. `

Where Any / All / None句

時には、複数のカラムに同じクエリ制約を適用する必要があるかもしれません。たとえば、指定されたリスト内の任意のカラムが指定された値にLIKEであるすべてのレコードを取得したい場合があります。これは、whereAnyメソッドを使用して実現できます:

  1. $users = DB::table('users')
  2. ->where('active', true)
  3. ->whereAny([
  4. 'name',
  5. 'email',
  6. 'phone',
  7. ], 'like', 'Example%')
  8. ->get();

上記のクエリは、次のSQLを生成します:

  1. SELECT *
  2. FROM users
  3. WHERE active = true AND (
  4. name LIKE 'Example%' OR
  5. email LIKE 'Example%' OR
  6. phone LIKE 'Example%'
  7. )

同様に、whereAllメソッドを使用して、指定されたすべてのカラムが指定された制約に一致するレコードを取得できます:

  1. $posts = DB::table('posts')
  2. ->where('published', true)
  3. ->whereAll([
  4. 'title',
  5. 'content',
  6. ], 'like', '%Laravel%')
  7. ->get();

上記のクエリは、次のSQLを生成します:

  1. SELECT *
  2. FROM posts
  3. WHERE published = true AND (
  4. title LIKE '%Laravel%' AND
  5. content LIKE '%Laravel%'
  6. )
  1. ``````php
  2. $posts = DB::table('albums')
  3. ->where('published', true)
  4. ->whereNone([
  5. 'title',
  6. 'lyrics',
  7. 'tags',
  8. ], 'like', '%explicit%')
  9. ->get();
  10. `

上記のクエリは、次のSQLを生成します:

  1. SELECT *
  2. FROM albums
  3. WHERE published = true AND NOT (
  4. title LIKE '%explicit%' OR
  5. lyrics LIKE '%explicit%' OR
  6. tags LIKE '%explicit%'
  7. )

JSON Where句

Laravelは、JSONカラムタイプをサポートするデータベースに対してJSONカラムをクエリすることもサポートしています。現在、これにはMariaDB 10.3+、MySQL 8.0+、PostgreSQL 12.0+、SQL Server 2017+、およびSQLite 3.39.0+が含まれます。JSONカラムをクエリするには、->演算子を使用します:

  1. $users = DB::table('users')
  2. ->where('preferences->dining->meal', 'salad')
  3. ->get();
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereJsonContains('options->languages', 'en')
  4. ->get();
  5. `

アプリケーションがMariaDB、MySQL、またはPostgreSQLデータベースを使用している場合は、whereJsonContainsメソッドに値の配列を渡すことができます:

  1. $users = DB::table('users')
  2. ->whereJsonContains('options->languages', ['en', 'de'])
  3. ->get();
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereJsonLength('options->languages', 0)
  4. ->get();
  5. $users = DB::table('users')
  6. ->whereJsonLength('options->languages', '>', 1)
  7. ->get();
  8. `

追加のWhere句

whereLike / orWhereLike / whereNotLike / orWhereNotLike

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereLike('name', '%John%')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereLike('name', '%John%', caseSensitive: true)
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->where('votes', '>', 100)
  4. ->orWhereLike('name', '%John%')
  5. ->get();
  6. `

whereNotLikeメソッドを使用して、クエリに「NOT LIKE」句を追加できます:

  1. $users = DB::table('users')
  2. ->whereNotLike('name', '%John%')
  3. ->get();

同様に、orWhereNotLikeを使用して、NOT LIKE条件を持つ「or」句を追加できます:

  1. $users = DB::table('users')
  2. ->where('votes', '>', 100)
  3. ->orWhereNotLike('name', '%John%')
  4. ->get();

whereLikeケースセンシティブ検索オプションは、現在SQL Serverではサポートされていません。

whereIn / whereNotIn / orWhereIn / orWhereNotIn

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereIn('id', [1, 2, 3])
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereNotIn('id', [1, 2, 3])
  4. ->get();
  5. `
  1. ``````php
  2. $activeUsers = DB::table('users')->select('id')->where('is_active', 1);
  3. $users = DB::table('comments')
  4. ->whereIn('user_id', $activeUsers)
  5. ->get();
  6. `

上記の例は、次のSQLを生成します:

  1. select * from comments where user_id in (
  2. select id
  3. from users
  4. where is_active = 1
  5. )

大量の整数バインディングをクエリに追加する場合、whereIntegerInRawまたはwhereIntegerNotInRawメソッドを使用してメモリ使用量を大幅に削減できます。

whereBetween / orWhereBetween

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereBetween('votes', [1, 100])
  4. ->get();
  5. `

whereNotBetween / orWhereNotBetween

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereNotBetween('votes', [1, 100])
  4. ->get();
  5. `

whereBetweenColumns / whereNotBetweenColumns / orWhereBetweenColumns / orWhereNotBetweenColumns

  1. ``````php
  2. $patients = DB::table('patients')
  3. ->whereBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
  4. ->get();
  5. `
  1. ``````php
  2. $patients = DB::table('patients')
  3. ->whereNotBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
  4. ->get();
  5. `

whereNull / whereNotNull / orWhereNull / orWhereNotNull

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereNull('updated_at')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereNotNull('updated_at')
  4. ->get();
  5. `

whereDate / whereMonth / whereDay / whereYear / whereTime

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereDate('created_at', '2016-12-31')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereMonth('created_at', '12')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereDay('created_at', '31')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereYear('created_at', '2016')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereTime('created_at', '=', '11:20:45')
  4. ->get();
  5. `

whereColumn / orWhereColumn

  1. ``````php
  2. $users = DB::table('users')
  3. ->whereColumn('first_name', 'last_name')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereColumn('updated_at', '>', 'created_at')
  4. ->get();
  5. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->whereColumn([
  4. ['first_name', '=', 'last_name'],
  5. ['updated_at', '>', 'created_at'],
  6. ])->get();
  7. `

論理グルーピング

時には、クエリの望ましい論理グルーピングを達成するために、いくつかの「where」句を括弧内にグループ化する必要があるかもしれません。実際、orWhereメソッドへの呼び出しを括弧内にグループ化することは、予期しないクエリの動作を避けるために一般的に常に行うべきです。これを実現するには、whereメソッドにクロージャを渡すことができます:

  1. $users = DB::table('users')
  2. ->where('name', '=', 'John')
  3. ->where(function (Builder $query) {
  4. $query->where('votes', '>', 100)
  5. ->orWhere('title', '=', 'Admin');
  6. })
  7. ->get();

ご覧のとおり、whereメソッドにクロージャを渡すことで、クエリビルダーに制約グループを開始するよう指示します。クロージャは、括弧グループ内に含めるべき制約を設定するために使用できるクエリビルダーインスタンスを受け取ります。上記の例は、次のSQLを生成します:

  1. select * from users where name = 'John' and (votes > 100 or title = 'Admin')
  1. <a name="advanced-where-clauses"></a>
  2. ### 高度なWhere句
  3. <a name="where-exists-clauses"></a>
  4. ### Where Exists句
  5. `````whereExists`````メソッドを使用すると、「where exists」SQL句を書くことができます。`````whereExists`````メソッドは、クエリビルダーインスタンスを受け取るクロージャを受け入れ、`````whereExists`````句内に配置するクエリを定義できます:
  6. ``````php
  7. $users = DB::table('users')
  8. ->whereExists(function (Builder $query) {
  9. $query->select(DB::raw(1))
  10. ->from('orders')
  11. ->whereColumn('orders.user_id', 'users.id');
  12. })
  13. ->get();
  14. `

または、クロージャの代わりにwhereExistsメソッドにクエリオブジェクトを提供することもできます:

  1. $orders = DB::table('orders')
  2. ->select(DB::raw(1))
  3. ->whereColumn('orders.user_id', 'users.id');
  4. $users = DB::table('users')
  5. ->whereExists($orders)
  6. ->get();

上記の2つの例は、次のSQLを生成します:

  1. select * from users
  2. where exists (
  3. select 1
  4. from orders
  5. where orders.user_id = users.id
  6. )

サブクエリWhere句

時には、サブクエリの結果を指定された値と比較する「where」句を構築する必要があるかもしれません。これは、whereメソッドにクロージャと値を渡すことで実現できます。たとえば、次のクエリは、指定されたタイプの最近の「メンバーシップ」を持つすべてのユーザーを取得します;

  1. use App\Models\User;
  2. use Illuminate\Database\Query\Builder;
  3. $users = User::where(function (Builder $query) {
  4. $query->select('type')
  5. ->from('membership')
  6. ->whereColumn('membership.user_id', 'users.id')
  7. ->orderByDesc('membership.start_date')
  8. ->limit(1);
  9. }, 'Pro')->get();

または、カラムをサブクエリの結果と比較する「where」句を構築する必要があるかもしれません。これは、カラム、演算子、およびクロージャをwhereメソッドに渡すことで実現できます。たとえば、次のクエリは、金額が平均より少ないすべての収入レコードを取得します;

  1. use App\Models\Income;
  2. use Illuminate\Database\Query\Builder;
  3. $incomes = Income::where('amount', '<', function (Builder $query) {
  4. $query->selectRaw('avg(i.amount)')->from('incomes as i');
  5. })->get();

全文検索Where句

全文検索Where句は、現在MariaDB、MySQL、およびPostgreSQLでサポートされています。

whereFullTextおよびorWhereFullTextメソッドを使用して、全文インデックスを持つカラムに対してクエリに全文「where」句を追加できます。これらのメソッドは、Laravelによって基盤となるデータベースシステムに適切なSQLに変換されます。たとえば、MATCH AGAINST句は、MariaDBまたはMySQLを利用するアプリケーションのために生成されます:

  1. $users = DB::table('users')
  2. ->whereFullText('bio', 'web developer')
  3. ->get();

順序付け、グルーピング、制限とオフセット

順序付け

orderByメソッド

  1. ``````php
  2. $users = DB::table('users')
  3. ->orderBy('name', 'desc')
  4. ->get();
  5. `

複数のカラムでソートするには、必要に応じてorderByを何度でも呼び出すことができます:

  1. $users = DB::table('users')
  2. ->orderBy('name', 'desc')
  3. ->orderBy('email', 'asc')
  4. ->get();

最新および最古のメソッド

  1. ``````php
  2. $user = DB::table('users')
  3. ->latest()
  4. ->first();
  5. `

ランダム順序付け

  1. ``````php
  2. $randomUser = DB::table('users')
  3. ->inRandomOrder()
  4. ->first();
  5. `

既存の順序付けの削除

reorderメソッドは、クエリに以前に適用されたすべての「order by」句を削除します:

  1. $query = DB::table('users')->orderBy('name');
  2. $unorderedUsers = $query->reorder()->get();

reorderメソッドを呼び出すときにカラムと方向を渡すことで、すべての既存の「order by」句を削除し、クエリにまったく新しい順序を適用できます:

  1. $query = DB::table('users')->orderBy('name');
  2. $usersOrderedByEmail = $query->reorder('email', 'desc')->get();

グルーピング

groupByおよびhavingメソッド

  1. ``````php
  2. $users = DB::table('users')
  3. ->groupBy('account_id')
  4. ->having('account_id', '>', 100)
  5. ->get();
  6. `
  1. ``````php
  2. $report = DB::table('orders')
  3. ->selectRaw('count(id) as number_of_orders, customer_id')
  4. ->groupBy('customer_id')
  5. ->havingBetween('number_of_orders', [5, 15])
  6. ->get();
  7. `
  1. ``````php
  2. $users = DB::table('users')
  3. ->groupBy('first_name', 'status')
  4. ->having('account_id', '>', 100)
  5. ->get();
  6. `

より高度なhavingステートメントを構築するには、havingRawメソッドを参照してください。

制限とオフセット

skipおよびtakeメソッド

  1. ``````php
  2. $users = DB::table('users')->skip(10)->take(5)->get();
  3. `

また、limitおよびoffsetメソッドを使用することもできます。これらのメソッドは、それぞれtakeおよびskipメソッドと機能的に同等です:

  1. $users = DB::table('users')
  2. ->offset(10)
  3. ->limit(5)
  4. ->get();

条件文

時には、他の条件に基づいてクエリに特定のクエリ句を適用したい場合があります。たとえば、特定の入力値が受信したHTTPリクエストに存在する場合にのみ、where文を適用したいかもしれません。これは、whenメソッドを使用して実現できます:

  1. $role = $request->input('role');
  2. $users = DB::table('users')
  3. ->when($role, function (Builder $query, string $role) {
  4. $query->where('role_id', $role);
  5. })
  6. ->get();
  1. `````when`````メソッドの第3引数として別のクロージャを渡すことができます。このクロージャは、最初の引数が`````false`````として評価される場合にのみ実行されます。この機能の使用方法を示すために、クエリのデフォルトの順序を設定するために使用します:
  2. ``````php
  3. $sortByVotes = $request->boolean('sort_by_votes');
  4. $users = DB::table('users')
  5. ->when($sortByVotes, function (Builder $query, bool $sortByVotes) {
  6. $query->orderBy('votes');
  7. }, function (Builder $query) {
  8. $query->orderBy('name');
  9. })
  10. ->get();
  11. `

挿入文

クエリビルダーは、データベーステーブルにレコードを挿入するために使用できるinsertメソッドも提供します。insertメソッドは、列名と値の配列を受け取ります:

  1. DB::table('users')->insert([
  2. 'email' => '',
  3. 'votes' => 0
  4. ]);

配列の配列を渡すことで、複数のレコードを一度に挿入できます。各配列は、テーブルに挿入されるべきレコードを表します:

  1. DB::table('users')->insert([
  2. ['email' => '', 'votes' => 0],
  3. ['email' => '', 'votes' => 0],
  4. ]);

insertOrIgnoreメソッドは、データベースにレコードを挿入する際にエラーを無視します。このメソッドを使用する場合、重複レコードエラーは無視され、データベースエンジンに応じて他の種類のエラーも無視される可能性があることに注意してください。たとえば、insertOrIgnoreMySQLの厳格モードをバイパスします

  1. DB::table('users')->insertOrIgnore([
  2. ['id' => 1, 'email' => ''],
  3. ['id' => 2, 'email' => ''],
  4. ]);
  1. ``````php
  2. DB::table('pruned_users')->insertUsing([
  3. 'id', 'name', 'email', 'email_verified_at'
  4. ], DB::table('users')->select(
  5. 'id', 'name', 'email', 'email_verified_at'
  6. )->where('updated_at', '<=', now()->subMonth()));
  7. `

自動インクリメントID

テーブルに自動インクリメントIDがある場合、insertGetIdメソッドを使用してレコードを挿入し、その後IDを取得します:

  1. $id = DB::table('users')->insertGetId(
  2. ['email' => '', 'votes' => 0]
  3. );

PostgreSQLを使用する場合、insertGetIdメソッドは自動インクリメント列がidという名前であることを期待します。異なる「シーケンス」からIDを取得したい場合は、insertGetIdメソッドの第2パラメータとして列名を渡すことができます。

アップサート

  1. ``````php
  2. DB::table('flights')->upsert(
  3. [
  4. ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
  5. ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
  6. ],
  7. ['departure', 'destination'],
  8. ['price']
  9. );
  10. `

上記の例では、Laravelは2つのレコードを挿入しようとします。同じdepartureおよびdestination列値を持つレコードがすでに存在する場合、Laravelはそのレコードのprice列を更新します。

SQL Serverを除くすべてのデータベースは、upsertメソッドの第2引数にある列が「プライマリ」または「ユニーク」インデックスを持つ必要があります。さらに、MariaDBおよびMySQLデータベースドライバは、upsertメソッドの第2引数を無視し、常にテーブルの「プライマリ」および「ユニーク」インデックスを使用して既存のレコードを検出します。

更新文

データベースにレコードを挿入することに加えて、クエリビルダーはupdateメソッドを使用して既存のレコードを更新することもできます。updateメソッドは、insertメソッドと同様に、更新する列を示す列と値のペアの配列を受け取ります。updateメソッドは、影響を受けた行の数を返します。updateクエリをwhere句を使用して制約することができます:

  1. $affected = DB::table('users')
  2. ->where('id', 1)
  3. ->update(['votes' => 1]);

更新または挿入

時には、データベース内の既存のレコードを更新したり、一致するレコードが存在しない場合は作成したりしたい場合があります。このシナリオでは、updateOrInsertメソッドを使用できます。updateOrInsertメソッドは、レコードを見つけるための条件の配列と、更新する列と値のペアの配列の2つの引数を受け取ります。

  1. ``````php
  2. DB::table('users')
  3. ->updateOrInsert(
  4. ['email' => '', 'name' => 'John'],
  5. ['votes' => '2']
  6. );
  7. `

一致するレコードの存在に基づいて、更新または挿入される属性をカスタマイズするために、updateOrInsertメソッドにクロージャを提供できます:

  1. DB::table('users')->updateOrInsert(
  2. ['user_id' => $user_id],
  3. fn ($exists) => $exists ? [
  4. 'name' => $data['name'],
  5. 'email' => $data['email'],
  6. ] : [
  7. 'name' => $data['name'],
  8. 'email' => $data['email'],
  9. 'marketable' => true,
  10. ],
  11. );

JSON列の更新

JSON列を更新する際は、->構文を使用してJSONオブジェクト内の適切なキーを更新する必要があります。この操作は、MariaDB 10.3以上、MySQL 5.7以上、PostgreSQL 9.5以上でサポートされています:

  1. $affected = DB::table('users')
  2. ->where('id', 1)
  3. ->update(['options->enabled' => true]);

インクリメントとデクリメント

クエリビルダーは、特定の列の値をインクリメントまたはデクリメントするための便利なメソッドも提供します。これらのメソッドは、少なくとも1つの引数を受け取ります:変更する列。列をインクリメントまたはデクリメントする量を指定するために、第2引数を提供することもできます:

  1. DB::table('users')->increment('votes');
  2. DB::table('users')->increment('votes', 5);
  3. DB::table('users')->decrement('votes');
  4. DB::table('users')->decrement('votes', 5);

必要に応じて、インクリメントまたはデクリメント操作中に更新する追加の列を指定することもできます:

  1. DB::table('users')->increment('votes', 1, ['name' => 'John']);

さらに、incrementEachおよびdecrementEachメソッドを使用して、複数の列を一度にインクリメントまたはデクリメントすることができます:

  1. DB::table('users')->incrementEach([
  2. 'votes' => 5,
  3. 'balance' => 100,
  4. ]);

削除文

クエリビルダーのdeleteメソッドを使用して、テーブルからレコードを削除できます。deleteメソッドは、影響を受けた行の数を返します。delete文を制約するには、deleteメソッドを呼び出す前に「where」句を追加します:

  1. $deleted = DB::table('users')->delete();
  2. $deleted = DB::table('users')->where('votes', '>', 100)->delete();

テーブル全体をトランケートしたい場合は、テーブルからすべてのレコードを削除し、自動インクリメントIDをゼロにリセットするtruncateメソッドを使用できます:

  1. DB::table('users')->truncate();

テーブルのトランケーションとPostgreSQL

PostgreSQLデータベースをトランケートする際は、CASCADEの動作が適用されます。これは、他のテーブルのすべての外部キー関連レコードも削除されることを意味します。

悲観的ロック

クエリビルダーには、select文を実行する際に「悲観的ロック」を達成するのに役立ついくつかの関数も含まれています。「共有ロック」でステートメントを実行するには、sharedLockメソッドを呼び出します。共有ロックは、選択された行がトランザクションがコミットされるまで変更されないようにします:

  1. DB::table('users')
  2. ->where('votes', '>', 100)
  3. ->sharedLock()
  4. ->get();

または、lockForUpdateメソッドを使用できます。「更新用」のロックは、選択されたレコードが変更されたり、別の共有ロックで選択されたりするのを防ぎます:

  1. DB::table('users')
  2. ->where('votes', '>', 100)
  3. ->lockForUpdate()
  4. ->get();

デバッグ

クエリを構築する際に、ddおよびdumpメソッドを使用して、現在のクエリバインディングとSQLをダンプできます。ddメソッドは、デバッグ情報を表示し、その後リクエストの実行を停止します。dumpメソッドは、デバッグ情報を表示しますが、リクエストの実行を続行します:

  1. DB::table('users')->where('votes', '>', 100)->dd();
  2. DB::table('users')->where('votes', '>', 100)->dump();
  1. ``````php
  2. DB::table('users')->where('votes', '>', 100)->dumpRawSql();
  3. DB::table('users')->where('votes', '>', 100)->ddRawSql();
  4. `