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

タイトル: 配列を条件にする方法
SEOタイトル: Laravel Query Builder で配列条件 (whereIn) 完全ガイド

この記事の要点
  • Laravel Query Builder で配列を条件にする基本: ->whereIn("id", [1,2,3])
  • 否定: ->whereNotIn("status", ["deleted", "banned"])
  • 複合 OR / AND は クロージャ ->where(function ($q) { ... }) でグルーピング
  • JSON カラムには ->whereJsonContains / ->whereJsonLength
  • PostgreSQL の配列型カラムは = ANY(ARRAY[...])whereRaw

基本: whereIn / whereNotIn

use Illuminate\Support\Facades\DB;
use App\Models\User;

// ID 配列で絞り込み (SQL: WHERE id IN (1, 2, 3))
$ids   = [1, 2, 3];
$users = User::whereIn('id', $ids)->get();
$users = DB::table('users')->whereIn('id', $ids)->get();

// 否定 (SQL: WHERE status NOT IN (...))
$active = User::whereNotIn('status', ['deleted', 'banned'])->get();

// 空配列を渡すと: whereIn は「常に false」、whereNotIn は「常に true」
User::whereIn('id', [])->get();      // → 必ず空 (WHERE 0=1)
User::whereNotIn('id', [])->get();   // → 全件 (WHERE 1=1)

// サブクエリ
$activeUserIds = User::where('status', 'active')->pluck('id');
$orders = Order::whereIn('user_id', $activeUserIds)->get();

// サブクエリ式
$orders = Order::whereIn('user_id', function ($q) {
    $q->select('id')->from('users')->where('status', 'active');
})->get();

複数カラムの IN (whereIn のタプル)

// 標準 SQL: (user_id, product_id) IN ((1, 100), (2, 200))
// Laravel では whereIn にカラム配列を渡せるバージョンあり (DBドライバ依存)
DB::table('orders')->whereIn(['user_id', 'product_id'], [
    [1, 100],
    [2, 200],
])->get();

// または whereRaw で書く
DB::table('orders')
  ->whereRaw('(user_id, product_id) IN ((?, ?), (?, ?))', [1, 100, 2, 200])
  ->get();

複合条件: クロージャでグルーピング

// (name LIKE ? OR email LIKE ?) AND status = 'active'
$users = User::where(function ($q) use ($keyword) {
        $q->where('name',  'LIKE', "%{$keyword}%")
          ->orWhere('email', 'LIKE', "%{$keyword}%");
    })
    ->where('status', 'active')
    ->get();

// 動的に条件を組み立てる
$query = User::query();

if ($keyword) {
    $query->where(function ($q) use ($keyword) {
        $q->where('name',  'LIKE', "%{$keyword}%")
          ->orWhere('email', 'LIKE', "%{$keyword}%");
    });
}

if (!empty($statuses)) {
    $query->whereIn('status', $statuses);
}

if ($from) $query->where('created_at', '>=', $from);
if ($to)   $query->where('created_at', '<=', $to);

$users = $query->orderBy('id')->paginate(20);

配列 (HashMap 風) を where() で展開

// 配列を渡すと AND で連結
$users = User::where([
    'status'   => 'active',
    'role'     => 'admin',
    'company_id' => 10,
])->get();
// → WHERE status='active' AND role='admin' AND company_id=10

// 各条件に演算子を指定したい場合
$users = User::where([
    ['age',     '>=', 20],
    ['status',  '=',  'active'],
    ['name',    'LIKE', 'A%'],
])->get();

JSON カラムの配列条件

MySQL 5.7+ / PostgreSQL の JSON / JSONB カラムは専用メソッドで条件指定できます:

// users.preferences = '{"languages": ["ja", "en"]}'

// JSON 配列に特定の値が含まれる
User::whereJsonContains('preferences->languages', 'ja')->get();

// 複数値すべて含む
User::whereJsonContains('preferences->languages', ['ja', 'en'])->get();

// JSON 配列の要素数
User::whereJsonLength('preferences->languages', '>=', 2)->get();

// JSON オブジェクトのキー値
User::where('preferences->theme', 'dark')->get();
// → WHERE JSON_EXTRACT(preferences, '$.theme') = 'dark'

// JSON カラムをアップデート
DB::table('users')
  ->where('id', 1)
  ->update(['preferences->theme' => 'light']);

PostgreSQL 配列型カラム

PostgreSQL は配列型 (text[], int[] 等)をネイティブにサポート。ANY / && / @> 演算子で条件指定:

// products.tags TEXT[] (例: ['ja', 'en', 'sale'])

// 'ja' が含まれる
DB::table('products')
  ->whereRaw("'ja' = ANY(tags)")
  ->get();

// 配列同士の重なり (1 つでも一致)
DB::table('products')
  ->whereRaw("tags && ARRAY['ja', 'en']::text[]")
  ->get();

// 配列の包含 (tags が指定配列を全て含む)
DB::table('products')
  ->whereRaw("tags @> ARRAY['ja', 'en']::text[]")
  ->get();

// バインドパラメータ版
DB::table('products')
  ->whereRaw('? = ANY(tags)', ['ja'])
  ->get();

IN サブクエリとの比較

方式使う場面性能
whereIn([...])固定配列・少件数 (~ 数千)速い
whereIn(クロージャ)サブクエリで動的取得オプティマイザ次第
whereExists存在チェック・大量データ速い
JOIN関連データ取得も同時に速い
IN(...) 大量パラメータ~ 数万件パラメータ上限 (MySQL: 65535、Oracle: 1000) に注意

性能上の注意

// ❌ 数万件の配列を whereIn → クエリが巨大化
$ids = range(1, 50000);
User::whereIn('id', $ids)->get();  // SQL が数 MB に

// ✅ 一時テーブルに INSERT してから JOIN
DB::statement('CREATE TEMPORARY TABLE tmp_ids (id BIGINT PRIMARY KEY)');
DB::table('tmp_ids')->insert(array_map(fn($id) => ['id' => $id], $ids));
$users = DB::table('users')
    ->join('tmp_ids', 'users.id', '=', 'tmp_ids.id')
    ->get();

// ✅ chunk で分割実行
foreach (array_chunk($ids, 1000) as $chunk) {
    User::whereIn('id', $chunk)->each(function ($user) {
        // 処理
    });
}

// ✅ サブクエリ版 (DB 内で完結)
$users = User::whereIn('id', function ($q) {
    $q->select('user_id')->from('orders')->where('status', 'completed');
})->get();

Eloquent の whereHas / whereRelation

// 「アクティブな注文を持つユーザー」
$users = User::whereHas('orders', function ($q) {
    $q->where('status', 'active');
})->get();

// Laravel 9+ のショートカット
$users = User::whereRelation('orders', 'status', 'active')->get();

// 注文を 5 件以上持つユーザー
$users = User::has('orders', '>=', 5)->get();

// 注文を持たない
$users = User::doesntHave('orders')->get();

FAQ

Q: 空配列を whereIn に渡すと SQL エラーになる?
A: Laravel は内部で安全に処理し、WHERE 0=1 相当に展開します。何も返らないだけでエラーにはなりません。

Q: whereIn に 1 万件の配列を渡しても大丈夫?
A: MySQL の max_allowed_packet (デフォルト 64MB) を超えるとエラー。Oracle は IN リスト 1000 件上限です。chunk 推奨。

Q: 配列の順序通りに結果を並べたい
A: orderByRaw("FIELD(id, " . implode(',', $ids) . ")") (MySQL)。PostgreSQL は array_position