2015年9月5日土曜日

PostgreSQL 無かったらINSERT文について

SQLはSELECT * FROM xxxくらいしか叩けない自分ですが、
DBを構築する必要が出てきたので色々と勉強中です。

早速ですが、DBにINSERTしたいレコードと同じものが無い場合のみINSERTしたい場合どうするか悩みました。

一度レコードの存在をSELECTで調べてその結果を一時的に保持して、
無ければ次にINSERTをすることも考えましたが、一度にそれをしたい!

早速ネットを調べてみると同じような質問が当然のごとくありました。
Postgres: INSERT if does not exist already

そして、この質問に対して次の様な回答がありました。
INSERT INTO example_table
    (id, name)
SELECT 1, 'John'
WHERE
    NOT EXISTS (
        SELECT id FROM example_table WHERE id = 1
    );

ほんのわずかなレースコンディションがあるようですが、これでやりたいことはできるようです。
しかし、なぜこれがうまく動くのかが理解できない!

で、INSERT、SELECT、NOT EXISTSをそれぞれ調べて次のことが分かり無事に理解できました。

  • NOT EXISTは続くSELECTの結果が無い場合trueを返す
  • SELECT 1, 'John'は1, 'John'を表示する
  • INSERT は()の後にSELECT文を書いてその結果を代入することができる
つまり、
  1. SELECT id FROM example_table WHERE id = 1で入れたいレコードがあるかを調べる
  2. WHERE NOT EXISTSで無かった場合実行するという条件を付ける
  3. 条件がtrueであった場合、SELECT 1, 'John'で代入したい値を指定する
  4. その値をINSERTする
ということだと理解しました。