#author("2025-01-09T20:34:37+09:00","","")
#author("2025-01-09T20:37:34+09:00","","")
[[Linuxめも]]

大量の新規登録と更新が混在しているCSVファイルを効率よくUPSERTしたい。

*テストデータ作成 [#t39e3920]

バージョン確認
 SELECT version();
 +-----------+
 | version() |
 +-----------+
 | 5.7.36    |
 +-----------+

product_code と item_code の組み合わせでユニーク。~
id は別テーブルと紐づいているので変更されるのはまずい。

テーブル作成
 CREATE TABLE product (
     id int AUTO_INCREMENT PRIMARY KEY,
     product_code varchar(255) NOT NULL,
     item_code varchar(255) NOT NULL,
     product_name varchar(255) NOT NULL,
     UNIQUE product_idx (product_code, item_code)
 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

テストデータ登録
 INSERT INTO product (product_code, item_code, product_name) VALUES
 ('pcode1', 'icode1', 'product1'),
 ('pcode2', 'icode2', 'product2'),
 ('pcode3', 'icode3', 'product3');

確認
 SELECT * FROM product;
 +----+--------------+-----------+--------------+
 | id | product_code | item_code | product_name |
 +----+--------------+-----------+--------------+
 |  1 | pcode1       | icode1    | product1     |
 |  2 | pcode2       | icode2    | product2     |
 |  3 | pcode3       | icode3    | product3     |
 +----+--------------+-----------+--------------+

*REPLACEは使えない [#v10a1eaf]

pcode1 の product_name を変更してみる。
 REPLACE product (product_code, item_code, product_name) VALUES ('pcode1', 'icode1', 'productA');
 Query OK, 2 rows affected (0.01 sec)

2 rows になるのはDELETEとINSERTが実行されるため。

確認
 SELECT * FROM product;
 +----+--------------+-----------+--------------+
 | id | product_code | item_code | product_name |
 +----+--------------+-----------+--------------+
 |  2 | pcode2       | icode2    | product2     |
 |  3 | pcode3       | icode3    | product3     |
 |  4 | pcode1       | icode1    | productA     |
 +----+--------------+-----------+--------------+

id が 1 だったものが 4 になっているのでREPLACEは使えない。

*ELTとFIELDを使う [#z6ad320e]

良い感じで実現できるらしいが記述がややこしかったので却下。

*ON DUPLICATE KEY UPDATEを使う [#pe3c10fb]

pcode1の商品名を戻して、pcode4を登録してみる。
 INSERT INTO product (product_code, item_code, product_name) VALUES
 ('pcode1', 'icode1', 'product1'),
 ('pcode4', 'icode4', 'product4')
 ON DUPLICATE KEY UPDATE product_name = VALUES(product_name);
 Query OK, 3 rows affected (0.01 sec)
 Records: 2  Duplicates: 1  Warnings: 0

確認
 SELECT * FROM product;
 +----+--------------+-----------+--------------+
 | id | product_code | item_code | product_name |
 +----+--------------+-----------+--------------+
 |  2 | pcode2       | icode2    | product2     |
 |  3 | pcode3       | icode3    | product3     |
 |  4 | pcode1       | icode1    | product1     |
 |  5 | pcode4       | icode4    | product4     |
 +----+--------------+-----------+--------------+

idは変わらず変更され、期待通りに登録された。


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS