はじめに
Laravelのデータベースクエリビルダーは、データベースクエリを作成し実行するための便利で流暢なインターフェースを提供します。これは、アプリケーション内のほとんどのデータベース操作を実行するために使用でき、Laravelがサポートするすべてのデータベースシステムと完全に連携します。
Laravelのクエリビルダーは、PDOパラメータバインディングを使用して、SQLインジェクション攻撃からアプリケーションを保護します。クエリビルダーに渡される文字列をクリーンアップまたはサニタイズする必要はありません。
PDOはカラム名のバインディングをサポートしていません。したがって、ユーザー入力がクエリで参照されるカラム名を決定することを決して許可しないでください。これには「order by」カラムも含まれます。
データベースクエリの実行
テーブルからすべての行を取得する
``````php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Show a list of all of the application's users.
*/
public function index(): View
{
$users = DB::table('users')->get();
return view('user.index', ['users' => $users]);
}
}
`
``````php
use Illuminate\Support\Facades\DB;
$users = DB::table('users')->get();
foreach ($users as $user) {
echo $user->name;
}
`
Laravelコレクションは、データをマッピングおよび削減するための非常に強力なメソッドを提供します。Laravelコレクションに関する詳細は、コレクションのドキュメントを参照してください。
テーブルから単一の行/カラムを取得する
データベーステーブルから単一の行を取得するだけが必要な場合は、DB
ファサードのfirst
メソッドを使用できます。このメソッドは、単一のstdClass
オブジェクトを返します:
$user = DB::table('users')->where('name', 'John')->first();
return $user->email;
データベーステーブルから単一の行を取得したいが、一致する行が見つからない場合はIlluminate\Database\RecordNotFoundException
をスローしたい場合は、firstOrFail
メソッドを使用できます。RecordNotFoundException
がキャッチされない場合、404 HTTPレスポンスが自動的にクライアントに返されます:
$user = DB::table('users')->where('name', 'John')->firstOrFail();
行全体が必要ない場合は、value
メソッドを使用してレコードから単一の値を抽出できます。このメソッドは、カラムの値を直接返します:
$email = DB::table('users')->where('name', 'John')->value('email');
``````php
$user = DB::table('users')->find(3);
`
カラム値のリストを取得する
単一のカラムの値を含むIlluminate\Support\Collection
インスタンスを取得したい場合は、pluck
メソッドを使用できます。この例では、ユーザーのタイトルのコレクションを取得します:
use Illuminate\Support\Facades\DB;
$titles = DB::table('users')->pluck('title');
foreach ($titles as $title) {
echo $title;
}
結果のコレクションが使用するカラムを指定するには、pluck
メソッドに2番目の引数を提供します:
$titles = DB::table('users')->pluck('title', 'name');
foreach ($titles as $name => $title) {
echo $title;
}
結果のチャンク処理
数千のデータベースレコードを操作する必要がある場合は、chunk
メソッドを使用することを検討してください。DB
ファサードが提供するこのメソッドは、結果の小さなチャンクを一度に取得し、各チャンクを処理のためにクロージャに渡します。たとえば、users
テーブル全体を100レコードずつチャンクで取得します:
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
foreach ($users as $user) {
// ...
}
});
クロージャからfalse
を返すことで、さらなるチャンクの処理を停止できます:
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
// Process the records...
return false;
});
結果をチャンク処理しながらデータベースレコードを更新している場合、チャンク結果が予期しない方法で変わる可能性があります。チャンク処理中に取得したレコードを更新する予定がある場合は、chunkById
メソッドを使用するのが最善です。このメソッドは、レコードの主キーに基づいて結果を自動的にページネートします:
DB::table('users')->where('active', false)
->chunkById(100, function (Collection $users) {
foreach ($users as $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
}
});
チャンクコールバック内でレコードを更新または削除する場合、主キーまたは外部キーの変更がチャンククエリに影響を与える可能性があります。これにより、レコードがチャンク結果に含まれない可能性があります。
遅延ストリーミング結果
``````php
use Illuminate\Support\Facades\DB;
DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
// ...
});
`
再度、取得したレコードを反復処理しながら更新する予定がある場合は、lazyById
またはlazyByIdDesc
メソッドを使用するのが最善です。これらのメソッドは、レコードの主キーに基づいて結果を自動的にページネートします:
DB::table('users')->where('active', false)
->lazyById()->each(function (object $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
});
反復処理中にレコードを更新または削除する場合、主キーまたは外部キーの変更がチャンククエリに影響を与える可能性があります。これにより、結果にレコードが含まれない可能性があります。
集計
クエリビルダーは、count
、max
、min
、avg
、およびsum
のような集計値を取得するためのさまざまなメソッドも提供します。クエリを構築した後に、これらのメソッドのいずれかを呼び出すことができます:
use Illuminate\Support\Facades\DB;
$users = DB::table('users')->count();
$price = DB::table('orders')->max('price');
もちろん、これらのメソッドを他の句と組み合わせて、集計値の計算方法を微調整することもできます:
$price = DB::table('orders')
->where('finalized', 1)
->avg('price');
レコードの存在を確認する
クエリの制約に一致するレコードが存在するかどうかを確認するために、count
メソッドを使用する代わりに、exists
およびdoesntExist
メソッドを使用できます:
if (DB::table('orders')->where('finalized', 1)->exists()) {
// ...
}
if (DB::table('orders')->where('finalized', 1)->doesntExist()) {
// ...
}
選択文
選択句の指定
データベーステーブルからすべてのカラムを選択したいわけではないかもしれません。select
メソッドを使用して、クエリのカスタム「select」句を指定できます:
use Illuminate\Support\Facades\DB;
$users = DB::table('users')
->select('name', 'email as user_email')
->get();
``````php
$users = DB::table('users')->distinct()->get();
`
すでにクエリビルダーインスタンスがあり、既存の選択句にカラムを追加したい場合は、addSelect
メソッドを使用できます:
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
生の式
時には、クエリに任意の文字列を挿入する必要があるかもしれません。生の文字列式を作成するには、raw
メソッドを使用します。DB
ファサードが提供します:
$users = DB::table('users')
->select(DB::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
生のステートメントは文字列としてクエリに注入されるため、SQLインジェクションの脆弱性を作成しないように非常に注意する必要があります。
生のメソッド
<a name="selectraw"></a>
#### selectRaw
`````selectRaw`````メソッドは、`````addSelect(DB::raw(/* ... */))`````の代わりに使用できます。このメソッドは、オプションのバインディング配列を第2引数として受け取ります:
``````php
$orders = DB::table('orders')
->selectRaw('price * ? as price_with_tax', [1.0825])
->get();
`
whereRaw / orWhereRaw
``````php
$orders = DB::table('orders')
->whereRaw('price > IF(state = "TX", ?, 100)', [200])
->get();
`
havingRaw / orHavingRaw
``````php
$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > ?', [2500])
->get();
`
orderByRaw
orderByRaw
メソッドを使用して、「order by」句の値として生の文字列を提供できます:
$orders = DB::table('orders')
->orderByRaw('updated_at - created_at DESC')
->get();
groupByRaw
groupByRaw
メソッドを使用して、group by
句の値として生の文字列を提供できます:
$orders = DB::table('orders')
->select('city', 'state')
->groupByRaw('city, state')
->get();
結合
内部結合句
クエリビルダーは、クエリに結合句を追加するためにも使用できます。基本的な「内部結合」を実行するには、クエリビルダーインスタンスでjoin
メソッドを使用します。join
メソッドに渡される最初の引数は、結合する必要があるテーブルの名前であり、残りの引数は結合のカラム制約を指定します。単一のクエリで複数のテーブルを結合することもできます:
use Illuminate\Support\Facades\DB;
$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();
左結合 / 右結合句
「内部結合」の代わりに「左結合」または「右結合」を実行したい場合は、leftJoin
またはrightJoin
メソッドを使用します。これらのメソッドは、join
メソッドと同じシグネチャを持っています:
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
$users = DB::table('users')
->rightJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
クロス結合句
``````php
$sizes = DB::table('sizes')
->crossJoin('colors')
->get();
`
高度な結合句
より高度な結合句を指定することもできます。開始するには、join
メソッドの第2引数としてクロージャを渡します。クロージャは、Illuminate\Database\Query\JoinClause
インスタンスを受け取り、「join」句に対する制約を指定できます:
DB::table('users')
->join('contacts', function (JoinClause $join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(/* ... */);
})
->get();
結合に「where」句を使用したい場合は、where
およびorWhere
メソッドをJoinClause
インスタンスが提供します。これらのメソッドは、2つのカラムを比較するのではなく、カラムを値と比較します:
DB::table('users')
->join('contacts', function (JoinClause $join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
サブクエリ結合
``````php
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function (JoinClause $join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})->get();
`
ラテラル結合
ラテラル結合は、PostgreSQL、MySQL >= 8.0.14、およびSQL Serverで現在サポートされています。
この例では、ユーザーのコレクションと、ユーザーの最近の3つのブログ投稿を取得します。各ユーザーは、結果セット内で最大3行を生成できます:それぞれの最近のブログ投稿のために。結合条件は、現在のユーザー行を参照する`````whereColumn`````句内で指定されます:
``````php
$latestPosts = DB::table('posts')
->select('id as post_id', 'title as post_title', 'created_at as post_created_at')
->whereColumn('user_id', 'users.id')
->orderBy('created_at', 'desc')
->limit(3);
$users = DB::table('users')
->joinLateral($latestPosts, 'latest_posts')
->get();
`
ユニオン
クエリビルダーは、2つ以上のクエリを「ユニオン」するための便利なメソッドも提供します。たとえば、最初のクエリを作成し、union
メソッドを使用して他のクエリとユニオンできます:
use Illuminate\Support\Facades\DB;
$first = DB::table('users')
->whereNull('first_name');
$users = DB::table('users')
->whereNull('last_name')
->union($first)
->get();
<a name="basic-where-clauses"></a>
## 基本的なwhere句
<a name="where-clauses"></a>
### where句
クエリビルダーの`````where`````メソッドを使用して、「where」句をクエリに追加できます。`````where`````メソッドへの最も基本的な呼び出しには、3つの引数が必要です。最初の引数はカラムの名前です。2番目の引数は演算子で、データベースがサポートする任意の演算子を使用できます。3番目の引数は、カラムの値と比較する値です。
たとえば、次のクエリは、`````votes`````カラムの値が`````100`````に等しく、`````age`````カラムの値が`````35`````より大きいユーザーを取得します:
``````php
$users = DB::table('users')
->where('votes', '=', 100)
->where('age', '>', 35)
->get();
`
便利なことに、カラムが=
に対して指定された値であることを確認したい場合は、where
メソッドに値を第2引数として渡すことができます。Laravelは、=
演算子を使用したいと仮定します:
$users = DB::table('users')->where('votes', 100)->get();
前述のように、データベースシステムがサポートする任意の演算子を使用できます:
$users = DB::table('users')
->where('votes', '>=', 100)
->get();
$users = DB::table('users')
->where('votes', '<>', 100)
->get();
$users = DB::table('users')
->where('name', 'like', 'T%')
->get();
``````php
$users = DB::table('users')->where([
['status', '=', '1'],
['subscribed', '<>', '1'],
])->get();
`
PDOはカラム名のバインディングをサポートしていません。したがって、ユーザー入力がクエリで参照されるカラム名を決定することを決して許可しないでください。「order by」カラムも含まれます。
Or Where句
クエリビルダーのwhere
メソッドへの呼び出しを連鎖させると、「where」句はand
演算子を使用して結合されます。ただし、orWhere
メソッドを使用して、or
演算子を使用してクエリに句を結合することができます。orWhere
メソッドは、where
メソッドと同じ引数を受け取ります:
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();
「or」条件を括弧内にグループ化する必要がある場合は、orWhere
メソッドに最初の引数としてクロージャを渡すことができます:
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere(function (Builder $query) {
$query->where('name', 'Abigail')
->where('votes', '>', 50);
})
->get();
上記の例は、次のSQLを生成します:
select * from users where votes > 100 or (name = 'Abigail' and votes > 50)
グローバルスコープが適用されるときに予期しない動作を避けるために、orWhere
呼び出しを常にグループ化する必要があります。
Where Not句
``````php
$products = DB::table('products')
->whereNot(function (Builder $query) {
$query->where('clearance', true)
->orWhere('price', '<', 10);
})
->get();
`
Where Any / All / None句
時には、複数のカラムに同じクエリ制約を適用する必要があるかもしれません。たとえば、指定されたリスト内の任意のカラムが指定された値にLIKE
であるすべてのレコードを取得したい場合があります。これは、whereAny
メソッドを使用して実現できます:
$users = DB::table('users')
->where('active', true)
->whereAny([
'name',
'email',
'phone',
], 'like', 'Example%')
->get();
上記のクエリは、次のSQLを生成します:
SELECT *
FROM users
WHERE active = true AND (
name LIKE 'Example%' OR
email LIKE 'Example%' OR
phone LIKE 'Example%'
)
同様に、whereAll
メソッドを使用して、指定されたすべてのカラムが指定された制約に一致するレコードを取得できます:
$posts = DB::table('posts')
->where('published', true)
->whereAll([
'title',
'content',
], 'like', '%Laravel%')
->get();
上記のクエリは、次のSQLを生成します:
SELECT *
FROM posts
WHERE published = true AND (
title LIKE '%Laravel%' AND
content LIKE '%Laravel%'
)
``````php
$posts = DB::table('albums')
->where('published', true)
->whereNone([
'title',
'lyrics',
'tags',
], 'like', '%explicit%')
->get();
`
上記のクエリは、次のSQLを生成します:
SELECT *
FROM albums
WHERE published = true AND NOT (
title LIKE '%explicit%' OR
lyrics LIKE '%explicit%' OR
tags LIKE '%explicit%'
)
JSON Where句
Laravelは、JSONカラムタイプをサポートするデータベースに対してJSONカラムをクエリすることもサポートしています。現在、これにはMariaDB 10.3+、MySQL 8.0+、PostgreSQL 12.0+、SQL Server 2017+、およびSQLite 3.39.0+が含まれます。JSONカラムをクエリするには、->
演算子を使用します:
$users = DB::table('users')
->where('preferences->dining->meal', 'salad')
->get();
``````php
$users = DB::table('users')
->whereJsonContains('options->languages', 'en')
->get();
`
アプリケーションがMariaDB、MySQL、またはPostgreSQLデータベースを使用している場合は、whereJsonContains
メソッドに値の配列を渡すことができます:
$users = DB::table('users')
->whereJsonContains('options->languages', ['en', 'de'])
->get();
``````php
$users = DB::table('users')
->whereJsonLength('options->languages', 0)
->get();
$users = DB::table('users')
->whereJsonLength('options->languages', '>', 1)
->get();
`
追加のWhere句
whereLike / orWhereLike / whereNotLike / orWhereNotLike
``````php
$users = DB::table('users')
->whereLike('name', '%John%')
->get();
`
``````php
$users = DB::table('users')
->whereLike('name', '%John%', caseSensitive: true)
->get();
`
``````php
$users = DB::table('users')
->where('votes', '>', 100)
->orWhereLike('name', '%John%')
->get();
`
whereNotLike
メソッドを使用して、クエリに「NOT LIKE」句を追加できます:
$users = DB::table('users')
->whereNotLike('name', '%John%')
->get();
同様に、orWhereNotLike
を使用して、NOT LIKE条件を持つ「or」句を追加できます:
$users = DB::table('users')
->where('votes', '>', 100)
->orWhereNotLike('name', '%John%')
->get();
whereLike
ケースセンシティブ検索オプションは、現在SQL Serverではサポートされていません。
whereIn / whereNotIn / orWhereIn / orWhereNotIn
``````php
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
`
``````php
$users = DB::table('users')
->whereNotIn('id', [1, 2, 3])
->get();
`
``````php
$activeUsers = DB::table('users')->select('id')->where('is_active', 1);
$users = DB::table('comments')
->whereIn('user_id', $activeUsers)
->get();
`
上記の例は、次のSQLを生成します:
select * from comments where user_id in (
select id
from users
where is_active = 1
)
大量の整数バインディングをクエリに追加する場合、whereIntegerInRaw
またはwhereIntegerNotInRaw
メソッドを使用してメモリ使用量を大幅に削減できます。
whereBetween / orWhereBetween
``````php
$users = DB::table('users')
->whereBetween('votes', [1, 100])
->get();
`
whereNotBetween / orWhereNotBetween
``````php
$users = DB::table('users')
->whereNotBetween('votes', [1, 100])
->get();
`
whereBetweenColumns / whereNotBetweenColumns / orWhereBetweenColumns / orWhereNotBetweenColumns
``````php
$patients = DB::table('patients')
->whereBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
->get();
`
``````php
$patients = DB::table('patients')
->whereNotBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
->get();
`
whereNull / whereNotNull / orWhereNull / orWhereNotNull
``````php
$users = DB::table('users')
->whereNull('updated_at')
->get();
`
``````php
$users = DB::table('users')
->whereNotNull('updated_at')
->get();
`
whereDate / whereMonth / whereDay / whereYear / whereTime
``````php
$users = DB::table('users')
->whereDate('created_at', '2016-12-31')
->get();
`
``````php
$users = DB::table('users')
->whereMonth('created_at', '12')
->get();
`
``````php
$users = DB::table('users')
->whereDay('created_at', '31')
->get();
`
``````php
$users = DB::table('users')
->whereYear('created_at', '2016')
->get();
`
``````php
$users = DB::table('users')
->whereTime('created_at', '=', '11:20:45')
->get();
`
whereColumn / orWhereColumn
``````php
$users = DB::table('users')
->whereColumn('first_name', 'last_name')
->get();
`
``````php
$users = DB::table('users')
->whereColumn('updated_at', '>', 'created_at')
->get();
`
``````php
$users = DB::table('users')
->whereColumn([
['first_name', '=', 'last_name'],
['updated_at', '>', 'created_at'],
])->get();
`
論理グルーピング
時には、クエリの望ましい論理グルーピングを達成するために、いくつかの「where」句を括弧内にグループ化する必要があるかもしれません。実際、orWhere
メソッドへの呼び出しを括弧内にグループ化することは、予期しないクエリの動作を避けるために一般的に常に行うべきです。これを実現するには、where
メソッドにクロージャを渡すことができます:
$users = DB::table('users')
->where('name', '=', 'John')
->where(function (Builder $query) {
$query->where('votes', '>', 100)
->orWhere('title', '=', 'Admin');
})
->get();
ご覧のとおり、where
メソッドにクロージャを渡すことで、クエリビルダーに制約グループを開始するよう指示します。クロージャは、括弧グループ内に含めるべき制約を設定するために使用できるクエリビルダーインスタンスを受け取ります。上記の例は、次のSQLを生成します:
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
<a name="advanced-where-clauses"></a>
### 高度なWhere句
<a name="where-exists-clauses"></a>
### Where Exists句
`````whereExists`````メソッドを使用すると、「where exists」SQL句を書くことができます。`````whereExists`````メソッドは、クエリビルダーインスタンスを受け取るクロージャを受け入れ、`````whereExists`````句内に配置するクエリを定義できます:
``````php
$users = DB::table('users')
->whereExists(function (Builder $query) {
$query->select(DB::raw(1))
->from('orders')
->whereColumn('orders.user_id', 'users.id');
})
->get();
`
または、クロージャの代わりにwhereExists
メソッドにクエリオブジェクトを提供することもできます:
$orders = DB::table('orders')
->select(DB::raw(1))
->whereColumn('orders.user_id', 'users.id');
$users = DB::table('users')
->whereExists($orders)
->get();
上記の2つの例は、次のSQLを生成します:
select * from users
where exists (
select 1
from orders
where orders.user_id = users.id
)
サブクエリWhere句
時には、サブクエリの結果を指定された値と比較する「where」句を構築する必要があるかもしれません。これは、where
メソッドにクロージャと値を渡すことで実現できます。たとえば、次のクエリは、指定されたタイプの最近の「メンバーシップ」を持つすべてのユーザーを取得します;
use App\Models\User;
use Illuminate\Database\Query\Builder;
$users = User::where(function (Builder $query) {
$query->select('type')
->from('membership')
->whereColumn('membership.user_id', 'users.id')
->orderByDesc('membership.start_date')
->limit(1);
}, 'Pro')->get();
または、カラムをサブクエリの結果と比較する「where」句を構築する必要があるかもしれません。これは、カラム、演算子、およびクロージャをwhere
メソッドに渡すことで実現できます。たとえば、次のクエリは、金額が平均より少ないすべての収入レコードを取得します;
use App\Models\Income;
use Illuminate\Database\Query\Builder;
$incomes = Income::where('amount', '<', function (Builder $query) {
$query->selectRaw('avg(i.amount)')->from('incomes as i');
})->get();
全文検索Where句
全文検索Where句は、現在MariaDB、MySQL、およびPostgreSQLでサポートされています。
whereFullText
およびorWhereFullText
メソッドを使用して、全文インデックスを持つカラムに対してクエリに全文「where」句を追加できます。これらのメソッドは、Laravelによって基盤となるデータベースシステムに適切なSQLに変換されます。たとえば、MATCH AGAINST
句は、MariaDBまたはMySQLを利用するアプリケーションのために生成されます:
$users = DB::table('users')
->whereFullText('bio', 'web developer')
->get();
順序付け、グルーピング、制限とオフセット
順序付け
orderByメソッド
``````php
$users = DB::table('users')
->orderBy('name', 'desc')
->get();
`
複数のカラムでソートするには、必要に応じてorderBy
を何度でも呼び出すことができます:
$users = DB::table('users')
->orderBy('name', 'desc')
->orderBy('email', 'asc')
->get();
最新および最古のメソッド
``````php
$user = DB::table('users')
->latest()
->first();
`
ランダム順序付け
``````php
$randomUser = DB::table('users')
->inRandomOrder()
->first();
`
既存の順序付けの削除
reorder
メソッドは、クエリに以前に適用されたすべての「order by」句を削除します:
$query = DB::table('users')->orderBy('name');
$unorderedUsers = $query->reorder()->get();
reorder
メソッドを呼び出すときにカラムと方向を渡すことで、すべての既存の「order by」句を削除し、クエリにまったく新しい順序を適用できます:
$query = DB::table('users')->orderBy('name');
$usersOrderedByEmail = $query->reorder('email', 'desc')->get();
グルーピング
groupByおよびhavingメソッド
``````php
$users = DB::table('users')
->groupBy('account_id')
->having('account_id', '>', 100)
->get();
`
``````php
$report = DB::table('orders')
->selectRaw('count(id) as number_of_orders, customer_id')
->groupBy('customer_id')
->havingBetween('number_of_orders', [5, 15])
->get();
`
``````php
$users = DB::table('users')
->groupBy('first_name', 'status')
->having('account_id', '>', 100)
->get();
`
より高度なhaving
ステートメントを構築するには、havingRaw
メソッドを参照してください。
制限とオフセット
skipおよびtakeメソッド
``````php
$users = DB::table('users')->skip(10)->take(5)->get();
`
また、limit
およびoffset
メソッドを使用することもできます。これらのメソッドは、それぞれtake
およびskip
メソッドと機能的に同等です:
$users = DB::table('users')
->offset(10)
->limit(5)
->get();
条件文
時には、他の条件に基づいてクエリに特定のクエリ句を適用したい場合があります。たとえば、特定の入力値が受信したHTTPリクエストに存在する場合にのみ、where
文を適用したいかもしれません。これは、when
メソッドを使用して実現できます:
$role = $request->input('role');
$users = DB::table('users')
->when($role, function (Builder $query, string $role) {
$query->where('role_id', $role);
})
->get();
`````when`````メソッドの第3引数として別のクロージャを渡すことができます。このクロージャは、最初の引数が`````false`````として評価される場合にのみ実行されます。この機能の使用方法を示すために、クエリのデフォルトの順序を設定するために使用します:
``````php
$sortByVotes = $request->boolean('sort_by_votes');
$users = DB::table('users')
->when($sortByVotes, function (Builder $query, bool $sortByVotes) {
$query->orderBy('votes');
}, function (Builder $query) {
$query->orderBy('name');
})
->get();
`
挿入文
クエリビルダーは、データベーステーブルにレコードを挿入するために使用できるinsert
メソッドも提供します。insert
メソッドは、列名と値の配列を受け取ります:
DB::table('users')->insert([
'email' => '',
'votes' => 0
]);
配列の配列を渡すことで、複数のレコードを一度に挿入できます。各配列は、テーブルに挿入されるべきレコードを表します:
DB::table('users')->insert([
['email' => '', 'votes' => 0],
['email' => '', 'votes' => 0],
]);
insertOrIgnore
メソッドは、データベースにレコードを挿入する際にエラーを無視します。このメソッドを使用する場合、重複レコードエラーは無視され、データベースエンジンに応じて他の種類のエラーも無視される可能性があることに注意してください。たとえば、insertOrIgnore
は MySQLの厳格モードをバイパスします:
DB::table('users')->insertOrIgnore([
['id' => 1, 'email' => ''],
['id' => 2, 'email' => ''],
]);
``````php
DB::table('pruned_users')->insertUsing([
'id', 'name', 'email', 'email_verified_at'
], DB::table('users')->select(
'id', 'name', 'email', 'email_verified_at'
)->where('updated_at', '<=', now()->subMonth()));
`
自動インクリメントID
テーブルに自動インクリメントIDがある場合、insertGetId
メソッドを使用してレコードを挿入し、その後IDを取得します:
$id = DB::table('users')->insertGetId(
['email' => '', 'votes' => 0]
);
PostgreSQLを使用する場合、insertGetId
メソッドは自動インクリメント列がid
という名前であることを期待します。異なる「シーケンス」からIDを取得したい場合は、insertGetId
メソッドの第2パラメータとして列名を渡すことができます。
アップサート
``````php
DB::table('flights')->upsert(
[
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
],
['departure', 'destination'],
['price']
);
`
上記の例では、Laravelは2つのレコードを挿入しようとします。同じdeparture
およびdestination
列値を持つレコードがすでに存在する場合、Laravelはそのレコードのprice
列を更新します。
SQL Serverを除くすべてのデータベースは、upsert
メソッドの第2引数にある列が「プライマリ」または「ユニーク」インデックスを持つ必要があります。さらに、MariaDBおよびMySQLデータベースドライバは、upsert
メソッドの第2引数を無視し、常にテーブルの「プライマリ」および「ユニーク」インデックスを使用して既存のレコードを検出します。
更新文
データベースにレコードを挿入することに加えて、クエリビルダーはupdate
メソッドを使用して既存のレコードを更新することもできます。update
メソッドは、insert
メソッドと同様に、更新する列を示す列と値のペアの配列を受け取ります。update
メソッドは、影響を受けた行の数を返します。update
クエリをwhere
句を使用して制約することができます:
$affected = DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
更新または挿入
時には、データベース内の既存のレコードを更新したり、一致するレコードが存在しない場合は作成したりしたい場合があります。このシナリオでは、updateOrInsert
メソッドを使用できます。updateOrInsert
メソッドは、レコードを見つけるための条件の配列と、更新する列と値のペアの配列の2つの引数を受け取ります。
``````php
DB::table('users')
->updateOrInsert(
['email' => '', 'name' => 'John'],
['votes' => '2']
);
`
一致するレコードの存在に基づいて、更新または挿入される属性をカスタマイズするために、updateOrInsert
メソッドにクロージャを提供できます:
DB::table('users')->updateOrInsert(
['user_id' => $user_id],
fn ($exists) => $exists ? [
'name' => $data['name'],
'email' => $data['email'],
] : [
'name' => $data['name'],
'email' => $data['email'],
'marketable' => true,
],
);
JSON列の更新
JSON列を更新する際は、->
構文を使用してJSONオブジェクト内の適切なキーを更新する必要があります。この操作は、MariaDB 10.3以上、MySQL 5.7以上、PostgreSQL 9.5以上でサポートされています:
$affected = DB::table('users')
->where('id', 1)
->update(['options->enabled' => true]);
インクリメントとデクリメント
クエリビルダーは、特定の列の値をインクリメントまたはデクリメントするための便利なメソッドも提供します。これらのメソッドは、少なくとも1つの引数を受け取ります:変更する列。列をインクリメントまたはデクリメントする量を指定するために、第2引数を提供することもできます:
DB::table('users')->increment('votes');
DB::table('users')->increment('votes', 5);
DB::table('users')->decrement('votes');
DB::table('users')->decrement('votes', 5);
必要に応じて、インクリメントまたはデクリメント操作中に更新する追加の列を指定することもできます:
DB::table('users')->increment('votes', 1, ['name' => 'John']);
さらに、incrementEach
およびdecrementEach
メソッドを使用して、複数の列を一度にインクリメントまたはデクリメントすることができます:
DB::table('users')->incrementEach([
'votes' => 5,
'balance' => 100,
]);
削除文
クエリビルダーのdelete
メソッドを使用して、テーブルからレコードを削除できます。delete
メソッドは、影響を受けた行の数を返します。delete
文を制約するには、delete
メソッドを呼び出す前に「where」句を追加します:
$deleted = DB::table('users')->delete();
$deleted = DB::table('users')->where('votes', '>', 100)->delete();
テーブル全体をトランケートしたい場合は、テーブルからすべてのレコードを削除し、自動インクリメントIDをゼロにリセットするtruncate
メソッドを使用できます:
DB::table('users')->truncate();
テーブルのトランケーションとPostgreSQL
PostgreSQLデータベースをトランケートする際は、CASCADE
の動作が適用されます。これは、他のテーブルのすべての外部キー関連レコードも削除されることを意味します。
悲観的ロック
クエリビルダーには、select
文を実行する際に「悲観的ロック」を達成するのに役立ついくつかの関数も含まれています。「共有ロック」でステートメントを実行するには、sharedLock
メソッドを呼び出します。共有ロックは、選択された行がトランザクションがコミットされるまで変更されないようにします:
DB::table('users')
->where('votes', '>', 100)
->sharedLock()
->get();
または、lockForUpdate
メソッドを使用できます。「更新用」のロックは、選択されたレコードが変更されたり、別の共有ロックで選択されたりするのを防ぎます:
DB::table('users')
->where('votes', '>', 100)
->lockForUpdate()
->get();
デバッグ
クエリを構築する際に、dd
およびdump
メソッドを使用して、現在のクエリバインディングとSQLをダンプできます。dd
メソッドは、デバッグ情報を表示し、その後リクエストの実行を停止します。dump
メソッドは、デバッグ情報を表示しますが、リクエストの実行を続行します:
DB::table('users')->where('votes', '>', 100)->dd();
DB::table('users')->where('votes', '>', 100)->dump();
``````php
DB::table('users')->where('votes', '>', 100)->dumpRawSql();
DB::table('users')->where('votes', '>', 100)->ddRawSql();
`