3
5

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 3 years have passed since last update.

PostgreSQL: レコードが無いときinsert、有るときupdateするにはon conflictを使う

Posted at

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だけ更新してね」ということになります。

豆知識

条件に応じてinsertupdateを使い分ける処理は、俗にupdateinsertの造語として「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だけ変更され、行は増えてないことが分かります。
3
5
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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?