バルクアップデートとは
バッチ処理などでは、データベースに複数の行を挿入したり、更新したりしたい場合がよくあると思います。挿入に関しては、大抵の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国際ライセンス)で公開します。