> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 查询构建器

> 介绍 Laravel `DB::table()` 查询构建器的基础与进阶用法，以及不使用 Eloquent 直接构建 SQL 的场景。

## 什么是查询构建器

Laravel 的查询构建器提供了一套流式接口来构建并执行数据库查询。从 `DB` 门面的 `table()` 方法开始，链式组合出查询。

```php theme={null}
use Illuminate\Support\Facades\DB;

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

底层使用 PDO 参数绑定，会自动防御 SQL 注入。

<Info>
  查询构建器可在 Laravel 支持的所有数据库（MySQL、MariaDB、PostgreSQL、SQLite、SQL Server）上运行，切换数据库时代码不变。
</Info>

## 与 Eloquent 的选择

| 场景               | 推荐       |
| ---------------- | -------- |
| 需要模型与关联          | Eloquent |
| 复杂聚合或报表          | 查询构建器    |
| 追求性能的大量数据处理      | 查询构建器    |
| 对已有表的简单操作        | 查询构建器    |
| 迁移 / Seeder 中的处理 | 查询构建器    |

## 读取数据

### 取全部

```php theme={null}
$users = DB::table('users')->get();

foreach ($users as $user) {
    echo $user->name;
}
```

`get()` 返回 `Illuminate\Support\Collection`。每条记录是 `stdClass` 对象。

### 取单条

```php theme={null}
// 第一条（无则 null）
$user = DB::table('users')->where('name', '山田太郎')->first();

// 无则抛异常（自动 404）
$user = DB::table('users')->where('name', '山田太郎')->firstOrFail();

// 只取某列的值
$email = DB::table('users')->where('name', '山田太郎')->value('email');

// 按 ID 查
$user = DB::table('users')->find(3);
```

### 抽取某列

```php theme={null}
$emails = DB::table('users')->pluck('email');
$emailByName = DB::table('users')->pluck('email', 'name');
```

### 大量数据分块处理

```php theme={null}
use Illuminate\Support\Collection;

// 每 100 条处理一次
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
    foreach ($users as $user) {
        // 处理...
    }
});

// 边处理边更新请用 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]);
        }
    });
```

<Warning>
  分块处理时若同时更新或删除记录，请使用 `chunkById()`。`chunk()` 可能出现记录偏移。
</Warning>

### 流式处理（LazyCollection）

```php theme={null}
DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
    // 一次处理一条
});
```

## 聚合

```php theme={null}
$count   = DB::table('users')->count();
$maxAge  = DB::table('users')->max('age');
$minAge  = DB::table('users')->min('age');
$avgAge  = DB::table('users')->avg('age');
$total   = DB::table('orders')->sum('amount');

$avgPremium = DB::table('orders')
    ->where('plan', 'premium')
    ->avg('amount');
```

### 是否存在

```php theme={null}
if (DB::table('orders')->where('finalized', 1)->exists()) {
    // 存在
}

if (DB::table('orders')->where('finalized', 1)->doesntExist()) {
    // 不存在
}
```

## SELECT 子句

```php theme={null}
$users = DB::table('users')
    ->select('name', 'email as user_email')
    ->get();

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

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

## WHERE 子句

### 基础条件

```php theme={null}
// 等于（= 可省略）
$users = DB::table('users')->where('votes', 100)->get();

// 指定比较运算符
$users = DB::table('users')->where('votes', '>=', 100)->get();
$users = DB::table('users')->where('name', 'like', '山田%')->get();

// 多条件（AND）
$users = DB::table('users')
    ->where('status', 'active')
    ->where('age', '>', 20)
    ->get();

// OR
$users = DB::table('users')
    ->where('votes', '>', 100)
    ->orWhere('name', '山田太郎')
    ->get();
```

### 条件分组

```php theme={null}
use Illuminate\Database\Query\Builder;

$users = DB::table('users')
    ->where('active', true)
    ->where(function (Builder $query) {
        $query->where('role', 'admin')
              ->orWhere('role', 'moderator');
    })
    ->get();
// WHERE active = 1 AND (role = 'admin' OR role = 'moderator')
```

### whereIn / whereBetween / whereNull

```php theme={null}
$users = DB::table('users')
    ->whereIn('id', [1, 2, 3])
    ->get();

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

$users = DB::table('users')
    ->whereBetween('age', [20, 40])
    ->get();

$users = DB::table('users')->whereNull('deleted_at')->get();
$users = DB::table('users')->whereNotNull('email_verified_at')->get();
```

### whereLike

```php theme={null}
// 默认忽略大小写
$users = DB::table('users')
    ->whereLike('name', '%山田%')
    ->get();

$users = DB::table('users')
    ->whereLike('name', '%Yamada%', caseSensitive: true)
    ->get();
```

### whereAny / whereAll

```php theme={null}
$users = DB::table('users')
    ->where('active', true)
    ->whereAny(['name', 'email', 'bio'], 'like', '%Laravel%')
    ->get();

$posts = DB::table('posts')
    ->whereAll(['title', 'content'], 'like', '%Laravel%')
    ->get();
```

### whereNullSafeEquals

`whereNullSafeEquals` / `orWhereNullSafeEquals` 将两个 NULL 也视为相等（对应 MySQL `<=>`、PostgreSQL `IS NOT DISTINCT FROM`）。

```php theme={null}
$lastLoginIp = $request->input('last_login_ip');

$users = DB::table('users')
    ->whereNullSafeEquals('last_login_ip', $lastLoginIp)
    ->get();
```

<Info>
  `where('column', null)` 会变成 `WHERE column IS NULL`，而 `whereNullSafeEquals('column', $value)` 无论 `$value` 是否为 null 都能一致工作，尤其适用于用户输入可能为 null 的场景。
</Info>

## JOIN

```php theme={null}
$users = DB::table('users')
    ->join('orders', 'users.id', '=', 'orders.user_id')
    ->select('users.name', 'orders.amount')
    ->get();

$users = DB::table('users')
    ->leftJoin('orders', 'users.id', '=', 'orders.user_id')
    ->get();

$users = DB::table('users')
    ->join('contacts', 'users.id', '=', 'contacts.user_id')
    ->join('orders', 'users.id', '=', 'orders.user_id')
    ->select('users.*', 'contacts.phone', 'orders.amount')
    ->get();
```

### 子查询 JOIN

```php theme={null}
$latestOrders = DB::table('orders')
    ->select('user_id', DB::raw('MAX(created_at) as last_order_at'))
    ->groupBy('user_id');

$users = DB::table('users')
    ->joinSub($latestOrders, 'latest_orders', function ($join) {
        $join->on('users.id', '=', 'latest_orders.user_id');
    })
    ->get();
```

## 排序 / 分组 / 限制

```php theme={null}
$users = DB::table('users')
    ->orderBy('name', 'asc')
    ->get();

$users = DB::table('users')
    ->orderBy('last_name')
    ->orderBy('first_name', 'desc')
    ->get();

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

$orders = DB::table('orders')
    ->select('status', DB::raw('COUNT(*) as count'))
    ->groupBy('status')
    ->get();

$orders = DB::table('orders')
    ->select('user_id', DB::raw('SUM(amount) as total'))
    ->groupBy('user_id')
    ->having('total', '>', 10000)
    ->get();

$users = DB::table('users')
    ->skip(10)
    ->take(5)
    ->get();
```

## 子查询

```php theme={null}
$activeUsers = DB::table('users')->select('id')->where('is_active', 1);

$comments = DB::table('comments')
    ->whereIn('user_id', $activeUsers)
    ->get();

$users = DB::table('users')
    ->select('name')
    ->selectSub(function ($query) {
        $query->from('orders')
              ->selectRaw('COUNT(*)')
              ->whereColumn('orders.user_id', 'users.id');
    }, 'order_count')
    ->get();
```

## Raw 表达式

<Warning>
  Raw 表达式会作为 SQL 字符串直接拼入。若直接传入用户输入会导致 SQL 注入。请务必使用绑定。
</Warning>

```php theme={null}
$users = DB::table('users')
    ->select(DB::raw('count(*) as user_count, status'))
    ->groupBy('status')
    ->get();

$orders = DB::table('orders')
    ->selectRaw('price * ? as price_with_tax', [1.10])
    ->get();

$orders = DB::table('orders')
    ->whereRaw('price > IF(state = "JP", ?, 100)', [500])
    ->get();

$orders = DB::table('orders')
    ->select('department', DB::raw('SUM(amount) as total'))
    ->groupBy('department')
    ->havingRaw('SUM(amount) > ?', [100000])
    ->get();

$orders = DB::table('orders')
    ->orderByRaw('updated_at - created_at DESC')
    ->get();
```

## INSERT / UPDATE / DELETE

### INSERT

```php theme={null}
DB::table('users')->insert([
    'email' => 'yamada@example.com',
    'name'  => '山田太郎',
]);

DB::table('users')->insert([
    ['email' => 'yamada@example.com', 'name' => '山田太郎'],
    ['email' => 'suzuki@example.com', 'name' => '铃木花子'],
]);

$id = DB::table('users')->insertGetId([
    'email' => 'sato@example.com',
    'name'  => '佐藤次郎',
]);
```

### UPSERT

```php theme={null}
DB::table('users')->upsert(
    [
        ['email' => 'yamada@example.com', 'name' => '山田太郎', 'votes' => 5],
        ['email' => 'suzuki@example.com', 'name' => '铃木花子', 'votes' => 10],
    ],
    uniqueBy: ['email'],
    update: ['name', 'votes']
);
```

### UPDATE

```php theme={null}
$affected = DB::table('users')
    ->where('id', 1)
    ->update(['name' => '山田一郎', 'updated_at' => now()]);

DB::table('users')->where('id', 1)->increment('votes');
DB::table('users')->where('id', 1)->increment('votes', 5);
DB::table('users')->where('id', 1)->decrement('votes');
DB::table('users')->where('id', 1)->decrement('balance', 100);
```

### DELETE

```php theme={null}
$deleted = DB::table('users')->where('status', 'inactive')->delete();

DB::table('users')->truncate();
```

## 按条件构建查询（when）

```php theme={null}
$status = request('status');
$sortBy = request('sort', 'name');

$users = DB::table('users')
    ->when($status, function ($query, $status) {
        $query->where('status', $status);
    })
    ->when($sortBy === 'email', function ($query) {
        $query->orderBy('email');
    }, function ($query) {
        $query->orderBy('name');
    })
    ->get();
```

## 调试

```php theme={null}
$sql = DB::table('users')->where('active', true)->toSql();
// "select * from `users` where `active` = ?"

$bindings = DB::table('users')->where('active', true)->getBindings();

// 输出后继续执行
DB::table('users')->where('active', true)->dump();

// 输出后终止
DB::table('users')->where('active', true)->dd();
```

<Tip>
  `dd()` 只用于调试，生产环境请勿使用。使用 `toSql()` 与 `getBindings()` 更安全。
</Tip>

## 小结

<AccordionGroup>
  <Accordion title="常用方法一览">
    | 方法                | 说明              |
    | ----------------- | --------------- |
    | `get()`           | 取全部（Collection） |
    | `first()`         | 取第一条            |
    | `find($id)`       | 按 ID 取          |
    | `value($column)`  | 取某字段的值          |
    | `pluck($column)`  | 取字段列表           |
    | `count()`         | 数量              |
    | `sum($col)`       | 求和              |
    | `avg($col)`       | 平均              |
    | `max($col)`       | 最大              |
    | `min($col)`       | 最小              |
    | `exists()`        | 是否存在            |
    | `insert([...])`   | 插入              |
    | `update([...])`   | 更新              |
    | `delete()`        | 删除              |
    | `chunk($n, fn)`   | 分块处理            |
    | `when($cond, fn)` | 条件构建            |
    | `toSql()`         | 查看生成 SQL        |
  </Accordion>

  <Accordion title="查询构建器 vs Eloquent">
    查询构建器比 Eloquent 更底层，返回 `stdClass` 而非模型实例。
    若不需要关联或模型事件（Observer），构建器更简单也更快。
  </Accordion>
</AccordionGroup>


## Related topics

- [集合](/zh/collections.md)
- [MongoDB](/zh/mongodb.md)
- [搜索](/zh/search.md)
- [用 Laravel 构建 MCP 服务器](/zh/advanced/mcp-server.md)
- [2026 年 3 月 Laravel 更新](/zh/blog/changelog/202603.md)
