バルクアップデートとは
バッチ処理などでは、データベースに複数の行を挿入したり、更新したりしたい場合がよくあると思います。挿入に関しては、大抵のRDBMSではINSERT INTO table (...) VALUES (...), (...)のような形で簡単に実行可能ですし、Laravelでもinsert()の第1引数に連想配列の配列を渡せば可能です。
更新に関してはそう簡単ではありませんが、MySQLに限っては、ELT()とFIELD()という2つの関数を使った方法で可能です。ただし、これをLaravelで実行するのはだいぶややこしいので、簡単に実行できるようにしてみました。
使い方
上記にあるサービスプロバイダクラスのファイルを、app/Providers以下に配置し、config/app.phpのprovidersにApp\Providers\MySqlBulkUpdateServiceProvider::classを追加、その上で、
<?php
DB::table('users')->whereNull('email_verified_at')->updateBulk([
['id' => 1, 'name' => 'admin1', 'email' => 'admin@example.com'],
['id' => 2, 'name' => 'admin2', 'email' => 'admin@example.com'],
['id' => 3, 'name' => 'admin3', 'email' => 'admin@example.com'],
]);
あるいは、
<?php
App\Models\User::whereNull('email_verified_at')->updateBulk([
['id' => 1, 'name' => 'admin1', 'email' => 'admin@example.com'],
['id' => 2, 'name' => 'admin2', 'email' => 'admin@example.com'],
['id' => 3, 'name' => 'admin3', 'email' => 'admin@example.com'],
]);
のように実行します。
詳細
第1引数で渡した配列から、id(Eloquent\Builderからの場合は、モデルに設定された主キー)あるいは第2引数で渡したカラムで検索し、残りの値を更新します。上記のQuery\Builderの例の場合は、以下のようなSQLにコンパイルされます。
UPDATE
`users`
SET
`name` = ELT(FIELD(`id`, ?, ?, ?), ?, ?, ?),
`email` = ?
WHERE
`email_verified_at` IS NULL
AND `id` IN (?, ?, ?)
emailは全行で同じとなっているため、ELT(), FIELD()は使わない形にします。また、updateBulk()以前に追加したWHERE句も別途設定されます。
さらに、Eloquent\Builder経由の場合はupdated_at等も自動で設定されます。
Query\Builder経由の実行時に、主キーがid以外の場合、あるいはEloquent\Builderで、主キー以外で検索したい場合は、第2引数にカラム名を指定します。
DB::table('users')->updateBulk([
['name' => 'admin1', 'email' => 'admin1@example.com'],
['name' => 'admin2', 'email' => 'admin2@example.com'],
['name' => 'admin3', 'email' => 'admin3@example.com'],
], 'email');
この記事のライセンス

この文書はCC BY(クリエイティブ・コモンズ表示4.0国際ライセンス)で公開します。