プライマリーキーや、ユニークキーが重複した際にUPDATEをかける、MySQLの便利な構文INSERT ON DUPLICATE KEY UPDATE
これを使って一括更新(挿入)する方法を今更ながら知りましたので、メモ!

テスト用のテーブルの準備


まず、こんなテーブルを作成。

CREATE TABLE `duplicate` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `value` varchar(255) NOT NULL,
  `update_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

で、適当にデータを入れておきます。

mysql> select * from duplicate;
+----+-------+---------------------+
| id | value | update_at           |
+----+-------+---------------------+
|  1 | hoge  | 0000-00-00 00:00:00 |
|  2 | fuga  | 0000-00-00 00:00:00 |
|  3 | piyo  | 0000-00-00 00:00:00 |
+----+-------+---------------------+

一行ずつなら問題ないが...


ON DUPLICATE KEY UPDATEを使い一行ずつインサートする場合だと、こんな感じでUPDATEしたいカラムと値を指定してます。

INSERT INTO duplicate (id, value) VALUES (1, 'new-value') ON DUPLICATE KEY UPDATE value = 'new-value';

でもこれだと、複数行のインサート時に「どうやって値を設定すればいいのか...」と悩んでいました。

解決方法を発見!


そこでドキュメントをよくよく見てみたところ、こんな書き方を発見!!

ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

実際に使ってみるとこんな感じです。

INSERT INTO `duplicate` (id, value) VALUES (1,'new-hoge'), (2, 'new-fuga'),(3,'new-piyo') ON DUPLICATE KEY UPDATE value=VALUES(`value`);

mysql> select * from duplicate;
+----+----------+---------------------+
| id | value    | update_at           |
+----+----------+---------------------+
|  1 | new-hoge | 2011-11-08 05:21:25 |
|  2 | new-fuga | 2011-11-08 05:21:25 |
|  3 | new-piyo | 2011-11-08 05:21:25 |
+----+----------+---------------------+

一括で更新でけた!!!

REPLACE INTOを使えば同じ様な事を実装できますが、REPLACE INTOだと新規挿入扱いになる為、ON UPDATE CURRENT_TIMESTAMPが使えません。。
それに、ON DUPLICATE KEY UPDATEなら、アプリケーションで利用する権限に削除権限を設定せずに済むので、何かと安心(?)。

ちゃんとドキュメントを読まないとなぁと思います。勉強します。