はじめに
LaravelでUPSERTを行いたい場合にupdateOrCreateメソッドを使った事があるかと思いますが、Laravel8系から一度で複数レコードのUPSERTを行える便利なupsertメソッドが出ていたので紹介したいと思います。
upsertメソッドとは
1つのクエリで複数レコードのUPSERT(すでに更新対象となるデータが存在すればUPDATEを実行し、無ければINSERTを行う)を簡潔に行う事が出来ます。
今まで同じ事をしようとする時は、数が少なければforeachで
updateOrCreate
メソッドで1レコードずつ処理したり、自前でSQLを用意してしていたかと思いますが、このメソッドを利用する事でスッキリと書けます。
使い方
例えば、usersテーブル(id、email、nameのカラム構成)でupsertメソッドを使ってみたいと思います。
例えば、id=1の1ユーザーのみ保存されている状態で以下の様にupsertメソッドを実行すると、
1 2 3 4 5 6 7 8 9 10 | $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カラムのみが更新されます。
引数で渡している値はそれぞれ
- 第一引数:UPSERT対象となるデータの配列。ここに第二引数と第三引数(省略しない場合)の値が含まれている必要があります。
- 第二引数:レコードのユニークを識別するカラムの配列。プライマリーキー or ユニークキー(複数もOK)
- 第三引数:UPDATEされる場合に更新したいカラムの配列。これを省略すると、全カラムが更新対象になるようです。
となっています。
usersテーブルでは、emailカラムにユニーク制約されているので、以下の様に書いても同じ結果が得られます。
1 2 | // 第二引数にユニークキーのemailを指定 User::upsert($users, ['email'], ['name']); |
タイムスタンプ
Userモデルでタイムスタンプが設定されていれば第三引数にタイムスタンプ用のカラムを含めなくても、
INSERT時には
created_at
と
updated_at
に値が入り、UPDATE時には
updated_at
のみ更新されます。
生成SQL
Mysqlの場合では、ON DUPLICATE KEY UPDATE ステートメントが生成されてました。
1 2 | // 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は色々便利な機能を追加してくれますね