はじめに
個人開発のバッチ処理を実装中に、「まとめてデータを追加する」「既にデータがあれば更新する」を同時に実施できるのか?の疑問がわいたのでとりまとめた。
結論
同時実行は「可能」
Bulk Insertとは
通常、MySQLでデータを追加するには1件づつ追加する場合はINSERT INTO
を使います。
INSER INTO users (id, name, age) VALUES (1, 'Alice', 25);
INSER INTO users (id, name, age) VALUES (2, 'Bob', 30);
しかし、1件ずつデータを追加するには処理が遅くなるため、MySQLではまとめてデータを追加するBulk Insert
というものがある。
INSERT INTO users (id, name, age)
VALUES
(1, 'Alice', 25),
(2, 'Bob', 30),
(3, 'Charlie', 28);
これなら、1回のクエリで複数のデータを一気に追加できるため、データ登録が効率化される。
ON DUPLICATE KEY UPDATE とは
もしid
を一意な値に制約している場合は、同じid
のデータを追加しようとするとエラーになってしまう。
INSERT INTO users (id, name, age) VALUES (1, 'Alice', 25);
INSERT INTO users (id, name, age) VALUES (1, 'Alice', 26); -- エラー!
これを「idが同じデータがあるなら上書き(更新)する」ようにするのがON DUPLICATE KEY UPDATE
である。
INSER INTO users (id, name, age)
VALUES(1, 'Alice', 26)
ON DUPLIVCATE KEY UPDATE
name = VALUES(name),
age = VALUES(age);
上記は、id=1
がある場合は、name
とage
を上書きするという意味になる。
Bulk Insert + ON DUPLICATE KEY UPDATE の組み合わせ
Bulk Insert (INSERT INTO ... VALUES (...), (...), (...)) も ON DUPLICATE KEY UPDATE も 一緒に使うことができる というのがポイント。
INSERT INTO users (id, name, age)
VALUES
(1, 'Alice', 26),
(2, 'Bob', 32),
(3, 'Charlie', 29)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
age = VALUES(age);
これを実行すると:
id=1, 2, 3 の データがなければ INSERT
id=1, 2, 3 の データがすでにあれば UPDATE(上書き)という意味となる。
VALUES() 関数とは
VALUES()
はON DUPLICATE KEY UPADATE
の時に使われる関数で、INSERT
で指定した値を取得するために使う。
ON DUPLICATE KEY UPDATE
name = VALUES(name),
age = VALUES(age);
このVALUES(name)
やVALUES(age)
は、INSERT
のVALUES(...)
に指定した値を指します。
具体例
例えば、毎日株価データを取得してデータベースに保存するとき、新しいデータはINSERTし、すでにあるデータはUPDATEすれば、データの二重登録を防ぎつつ最新の情報を保持できます。
INSERT INTO stock_prices (compnay_code, date, close_pise)
VALUES
('72030', '2025-03-15', 1200),
('83060', '2025-03-15', 850)
ON DUPLICATE KEY UPDATE
close_price = VALUES(close_price);
このようにすると、同じ company_code & dateのデータがある場合はUPDATEされるので、古い株価データを更新が可能となる。
さいごに
-
Bulk Insert
は複数のデータを一括でINSERTできるので速い。 -
ON DUPLICATE KEY UPDATE
を使うと、すでにあるデータはUPDATEできるので、重複エラーを防げる。 - 両方を組み合わせると、一括追加しつつ、既存データを上書きすることができる。
- VALUES() 関数は INSERT のときに指定した値を参照するために使う。