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

タイトル: INSERT
SEOタイトル: Laravel INSERT クエリビルダ完全ガイド

この記事の要点
  • クエリビルダ基本: DB::table("users")->insert(["name" => "taro"])
  • auto increment ID 取得: insertGetId() が新規 ID を返す
  • 複数行 INSERT: 連想配列の配列を渡すと一括挿入 (1 クエリ)
  • insertOrIgnore / upsert で重複時の挙動を制御
  • Eloquent Model::create()$fillable 必須、Mass Assignment 例外対策
  • PDO の prepared statement により自動でエスケープされ SQL インジェクション安全

クエリビルダによる INSERT の基本

Laravel の DB::table() から呼び出すクエリビルダは、生 SQL を書かずに型安全に INSERT を発行できます。最低限の構文は以下のとおりです。

use Illuminate\Support\Facades\DB;

// 1 行挿入
DB::table('users')->insert([
    'name'       => 'taro',
    'email'      => 'taro@example.com',
    'created_at' => now(),
    'updated_at' => now(),
]);

内部的には INSERT INTO users (name, email, created_at, updated_at) VALUES (?, ?, ?, ?) と prepared statement になり、値は PDO 側でエスケープされます。シングルクオートやセミコロンを含む値でも SQL インジェクションになりません。

auto increment ID を取得する

挿入直後にその行の主キーが欲しい場合は insertGetId() を使います。戻り値は新しい ID (int) です。

$id = DB::table('users')->insertGetId([
    'name'  => 'jiro',
    'email' => 'jiro@example.com',
]);

// PostgreSQL 等で別カラム名のシーケンスを使う場合は第二引数で指定
$id = DB::table('orders')->insertGetId($data, 'order_id');

複数行を一括 INSERT

連想配列の配列を渡すと INSERT ... VALUES (...), (...), (...) という単一クエリで挿入されます。N 行を N 回の INSERT で投げるのに比べてはるかに高速です。

DB::table('users')->insert([
    ['name' => 'taro', 'email' => 'taro@example.com'],
    ['name' => 'jiro', 'email' => 'jiro@example.com'],
    ['name' => 'saburo', 'email' => 'saburo@example.com'],
]);

// 巨大配列はチャンク化(MySQL は max_allowed_packet 制限あり)
collect($bigRows)->chunk(1000)->each(function ($chunk) {
    DB::table('logs')->insert($chunk->toArray());
});

insertOrIgnore — 重複時は無視

UNIQUE 制約違反のときに例外を投げず黙ってスキップしたいなら insertOrIgnore()。戻り値は実際に挿入された行数です。

$inserted = DB::table('email_subscribers')->insertOrIgnore([
    ['email' => 'a@example.com'],
    ['email' => 'b@example.com'],
    ['email' => 'a@example.com'],   // 重複 → 無視
]);
// $inserted = 2

upsert — INSERT or UPDATE

主キー or UNIQUE キーで衝突したら指定カラムを UPDATE します。MySQL の ON DUPLICATE KEY UPDATE、PostgreSQL の ON CONFLICT を抽象化したものです。

DB::table('product_stocks')->upsert(
    [
        ['product_id' => 1, 'qty' => 10],
        ['product_id' => 2, 'qty' => 5],
    ],
    ['product_id'],   // 一意キー
    ['qty']           // 衝突時に上書きするカラム
);

Eloquent モデルでの INSERT

Eloquent では create() または save() を使います。$fillable 未設定だと Mass Assignment 例外が発生するので注意してください。

class User extends Model
{
    protected $fillable = ['name', 'email'];
}

// 一括代入 + 保存
$user = User::create([
    'name'  => 'taro',
    'email' => 'taro@example.com',
]);

// 個別代入
$u = new User();
$u->name  = 'jiro';
$u->email = 'jiro@example.com';
$u->save();

// 重複なら作成しない
User::firstOrCreate(
    ['email' => 'taro@example.com'],   // 検索条件
    ['name'  => 'taro']                // 無ければ作る値
);

クエリビルダ vs Eloquent vs 生 SQL

方法用途速度イベント
DB::insert() 生 SQL特殊な SQL を直接書きたい★★★無し
クエリビルダ insert()シンプル / 大量バッチ★★★無し (モデルイベント不発火)
Eloquent create()1 件ずつ、属性キャスト / リレーション利用★★creating / created 発火

トランザクションと組み合わせる

DB::transaction(function () {
    $userId = DB::table('users')->insertGetId([
        'name'  => 'taro',
        'email' => 'taro@example.com',
    ]);

    DB::table('user_profiles')->insert([
        'user_id' => $userId,
        'bio'     => 'hello',
    ]);
}, 3); // 第二引数はデッドロック時のリトライ回数

途中で例外が出ると自動 ROLLBACK されます。明示的に DB::beginTransaction() / DB::commit() / DB::rollBack() を呼ぶこともできます。

よくあるエラーと対処

エラー原因対処
SQLSTATE[23000] Duplicate entryUNIQUE 制約違反insertOrIgnore / upsert
MassAssignmentException$fillable 未設定Eloquent モデルに $fillable 追加
Field doesn't have a default valueNOT NULL カラムを未指定カラムに値 or DB 側で DEFAULT
SQLSTATE[HY000] [2006] MySQL server has gone away大量 INSERT で max_allowed_packet 超過チャンク化 or max_allowed_packet

FAQ

Q: Eloquent の create() でタイムスタンプが入らない
A: モデルで public $timestamps = true; (デフォルト) かつテーブルに created_at / updated_at が必要です。クエリビルダ insert() は自動で入れてくれません。

Q: insert 後の ID が 0 になる
A: insert() は bool を返します。ID が欲しい場合は必ず insertGetId() を使ってください。

Q: 数万件を高速で入れたい
A: チャンク化した一括 INSERT + DB::transaction() でくくる + 不要なインデックスは一時的に ALTER TABLE ... DISABLE KEYS