MySQLのINSERT ... ON DUPLICATE KEY UPDATE ...
構文って、すごく便利ですよね。↓みたいなケースはよく発生すると思うのですが、一つのSQLで書けてしまいます。
- レコードが存在しなければ、INSERT。
- レコードが既に存在していれば、指定したカラムだけUPDATE。
愚直にやるとSELECTして実在確認してから、INSERTかUPDATEか出しわける、みたいなことになるので、必ず2回のクエリになってしまうところを、1回のクエリでエレガントに書けます。
SQLiteでも似たようなことがしたくて調べたところ、INSERT OR REPLACE ...
構文がありました。しかしちょっとやりたいことと違うみたい。
REPLACE構文は、UNIQUE制約/主キーのダブりでINSERTが失敗した場合、邪魔になったレコードを削除してから新しくINSERTしようとします。これだと、AUTO INCREMENTなキー列の値が変わってしまいます。
SQLite Query Language: ON CONFLICT clause
なので、ON DUPLICATE KEY UPDATEと同じことをしたい場合は、2回のクエリで書くしかないみたいです。といってもSELECTしなくてもOK。
- とりあえず
INSERT OR IGNORE ...
を投げる。 - ホスト言語側でINSERT文の影響行数を調べて、0行だったら(=INSERTに失敗していれば)
UPDATE ...
を実行する。
この書き方なら、新規の時は1クエリで済むので、愚直にSELECTするよりは効率がよさそうです。
あー、もしくはこっちでもいいかもな。先にUPDATEすれば、更新の方が新規登録より多いようなケースに最適化されそう。
- とりあえず
UPDATE ...
を投げる。 - ホスト言語側でUPDATE文の影響行数を調べて、0行だったら(=UPDATEに失敗していれば)
INSERT ...
を実行する。
まあSQLiteはネットワーク越しに操作することはないので、クエリの数が多少増えても気にならないのかもしれません。