PostgreSQLでprimary keyに該当するレコードがまだ無いときはinsert
し、すでに有る場合はupdate
するクエリを紹介します。
MySQLでいうところのINSERT ... ON DUPLICATE KEY UPDATE
です。
PostgreSQLで、 レコードが無いときinsert
、有るときupdate
するにはon conflict
を使います:
insert into product (id, name) values (1, 'item 1')
on conflict on constraint product_pk
do update set name='item 1';
ちょっとした説明
productテーブルにはid
カラムがあります。このid
カラムにはprimary key制約がついていて、その制約名が「product_pk」です。on conflict on constraint
は「制約に引っかかったとき」という意味です。ここでは、product_pk
制約に引っかかったとき、つまり、insert
しようとしてid
が重複していたときに、何かするという意味になります。この何かするの部分がdo
以降のupdate
句の内容になります。そのupdate
句ではname
カラムだけ更新するようになっています。したがって、クエリの意味をまとめると、「IDを指定してレコードを追加するんだけど、もしIDがすでに存在するなら、nameだけ更新してね」ということになります。
豆知識
条件に応じてinsert
とupdate
を使い分ける処理は、俗にupdate
とinsert
の造語として「upsert」と呼ばれます。
実行例
-- テーブルを作ります。product_pk制約も同時に作れます。
create table product
(id serial not null constraint product_pk primary key,
name varchar);
-- 初回のinsert
insert into product (id, name) values (1, 'product name')
on conflict on constraint product_pk
do update set name='product name';
-- テーブルの中身を確認
select * from product;
-- id | name
-- ----+--------
-- 1 | product name
-- (1 row)
-- 二回目のクエリ
insert into product (id, name) values (1, 'new name')
on conflict on constraint product_pk
do update set name='new name';
-- テーブルの中身を確認
select * from product;
-- id | name
-- ----+--------
-- 1 | new name
-- (1 row)
-- エラーにならず、nameだけ変更され、行は増えてないことが分かります。