LaravelでUPSERTを行いたい場合にupdateOrCreateメソッドを使った事があるかと思いますが、Laravel8系から一度で複数レコードのUPSERTを行える便利なupsertメソッドが出ていたので紹介したいと思います。
1つのクエリで複数レコードのUPSERT(すでに更新対象となるデータが存在すればUPDATEを実行し、無ければINSERTを行う)を簡潔に行う事が出来ます。
今まで同じ事をしようとする時は、数が少なければforeachでupdateOrCreate
メソッドで1レコードずつ処理したり、自前でSQLを用意してしていたかと思いますが、このメソッドを利用する事でスッキリと書けます。
例えば、usersテーブル(id、email、nameのカラム構成)でupsertメソッドを使ってみたいと思います。
例えば、id=1の1ユーザーのみ保存されている状態で以下の様にupsertメソッドを実行すると、
$users = [ // UPDATEされる ['id' => 1, 'email' => 'test1@test.com', 'name' => 'テスト11'], // INSERTされる ['id' => 2, 'email' => 'test2@test2.com', 'name' => 'テスト2'], // INSERTされる ['id' => 3, 'email' => 'test3@test3.com', 'name' => 'テスト3'] ]; User::upsert($users, ['id'], ['name']);
id=1のレコードは既に存在しているのでUPDATEされ、id=1以外のレコードはINSERTされます。
UPDATEされるレコードでは、nameカラムのみが更新されます。
引数で渡している値はそれぞれ
となっています。
usersテーブルでは、emailカラムにユニーク制約されているので、以下の様に書いても同じ結果が得られます。
// 第二引数にユニークキーのemailを指定 User::upsert($users, ['email'], ['name']);
Userモデルでタイムスタンプが設定されていれば第三引数にタイムスタンプ用のカラムを含めなくても、
INSERT時にはcreated_at
とupdated_at
に値が入り、UPDATE時にはupdated_at
のみ更新されます。
Mysqlの場合では、ON DUPLICATE KEY UPDATE ステートメントが生成されてました。
// on duplicate key updateステートメント insert into `users` (`created_at`, `email`, `id`, `name`, `updated_at`) values (?, ?, ?, ?, ?), (?, ?, ?, ?, ?) on duplicate key update `name` = values(`name`), `updated_at` = values(`updated_at`)
upsertメソッドを利用すると、簡潔に複数レコードのUPSERTを行う事が出来ます。Laravelは色々便利な機能を追加してくれますね