背景
複数のレコードの更新をかける際に、キーとなるカラムに値が重複している場合は更新、なければ挿入
という処理をしたかったが、うまくいかずにハマってもた。
どんどんレコードが増えていくのでなんでやん!って叫びながら作業をしていた。
そんな自分が悲しくて、備忘録として残す。
upsertにはunique indexが必要
単純に第2引数に重複チェックしたいカラム名を渡すだけではアカンのです。
とある記事には
第2引数にはユニークキーやプライマリキーを指定すると良い
という旨の記載があったが、語弊があるんやん?
- ❌ すると良い (should)
- ⭕️ せなあかん (must)
つまり、ユニークキーあるいはプライマリキーを指定しなければ重複チェックは行われないが正しい。
ちゃんとドキュメントにも記載がある。
SQL Server以外のすべてのデータベースでは、upsertメソッドの第2引数のカラムへ"primary"、または"unique"インデックスを指定する必要があります。さらに、MySQLデータベースドライバは、upsertメソッドの第2引数を無視し、常にテーブルの"primary"および"unique"インデックスを既存レコードの検出に使用します。
わいの使ってるのはMySQLやったさかい、必要。shouldやなくてmustやったって話や。
第2引数のdepartureとdestinationはprimary OR uniqueインデックスが必要ということ
Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
もし今はインデックスがないテーブルに対してupsertを使いたければインデックスを追加する必要がある。せなあかん。
uniqueインデックスを追加する
ALTER TABLE flights ADD UNIQUE departure (departure);
ALTER TABLE flights ADD UNIQUE destination (destination);
// 実行する前に、重複したデータが存在しないことを確認する必要あり。重複しているとインデックスが追加できない。
もしインデックスを追加できなければupdateOrCreateであるしかないかな。
bulk処理ができへんけども、、、