11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MySQLのLOAD DATA INFILEを使って登録または更新する方法

Posted at

初投稿

できるエンジニアは良質なアウトプットをしてるな~と感じたので、僭越ながら投稿させていただきます。

やりたいこと

CSVファイルをテーブルに一括で取り込む際に、PRIMARY KEYまたはUNIQUEな値がすでに存在していたら、更新処理を行い、なければ登録処理を行う。
(ちなみにバージョンはPHP5.6、MySQL5.6)

実現方法

◆PDOのfetch使って一件一件ゴリゴリやる?

まず最初に思いついたのがこれ。
ループさせながら、一行とっては「ON DUPLICATE KEY UPDATE」構文を使って登録/更新していく。
う~ん、データ量が小さければいいけど、多くなると遅いなー。もっと効率よくできないものか。

◆「LOAD DATA INFILE」 構文という便利なものがあった!

参考1 参考2
リファレンスマニュアルによると、「INSERT ステートメントを多数使用する場合と比較して、20 倍速度が上がる。」らしい。
これはすごい。あれ、でもこれって登録処理できても更新処理できなくない?

◆「REPLACE」 構文を使えばできそう?

参考3
あ、なんだ、「LOAD DATA INFILE」の中に「REPLACE」指定すれば、PRIMARY KEYまたはUNIQUEな値がテーブルに存在していなければ登録、存在していれば更し、、、あれ、更新じゃなくてDELETEしてINSERTされるっぽいぞ!!!
これでは更新処理で更新したくない値(データの新規登録日など)も更新されてしまう、、

◆構文を組み合わせてなんとか実現できた!

ちょっと面倒だが、以下の手順を踏めば、「やりたいこと」が満たせた。

  1. 一時的に取り込み用のテーブルを用意する
    CREATE TABLE tmp_table LIKE main_table;
    →一時的に取り込むテーブルがすでに用意されている場合は、中身を消しておく
    TRUNCATE TABLE tmp_table;
  2. 一時的に取り込むテーブルに「LOAD DATA INFILE」して取り込む
    LOAD DATA INFILE 'file.csv' INTO TABLE tmp_table FIELDS TERMINATED BY ',' ;
  3. 取り込みたいテーブルに「ON DUPLICATE KEY UPDATE」して取り込む
    INSERT INTO main_table SELECT * FROM tmp_table ON DUPLICATE KEY UPDATE main_field1 = VALUES(field1), main_field2 = VALUES(field2);
◆おわりに

最後まで読んでくださり有難うございました。
内容に不備などありましたら、ご指導お願いします。

それでは、またなんか内容見つけて投稿しよ~
さようなら~

11
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?