データベース - SQL 基本構文 - INSERT - UPSERT

 クラウディア
1. 概要
2. ON CONFLICT
3. 複数キー

1. 概要

 デーブルに同値のものがなければ「INSERT」、あれば「UPDATE」したい。  よくある場面です。  初歩のころは、同値のものがあったら、いったん「DELETE」して「INSERT」していましたが・・・。  これには、いろいろな方法があるようです。  本ページは、下記のサイトを参考にさせていただきました。
PostgreSQL で「あれば UPDATE、なければ INSERT」の UPSERT をやってみる」
「主キーの有無により insert と update を切り替えるには merge を活用する #SQL」
「UPSERT 大全2022

2. ON CONFLICT

 「postgreSQL 9.5」以上であれば、使えます。  というか、2023年11月9日時点では、これしか知りませんでした。  「postgreSQL」のドキュメントでは「INSERT」に記載があります。

INSERT INTO
	テーブル
	(カラム1, カラム2...)
VALUES
	(値1, 値2...)
ON CONFLICT
	(カラム1)
DO UPDATE
	SET
		カラム2 = 値2...;
 てな感じで思い通りのことができるようです。  おを、便利。  ただし、参考サイトにあるように、「CONFLICT」で比較するカラムはユニークでないととんでもないことになるかエラーになります。  まぁ、通常はプライマリキーで使うのでしょう。  「ON CONFLICT」に指定できるカラムが1つかないみたいなので、困ったなぁと思っていたら・・・。  「PostgreSQL 9.5 の新機能 CONFLICT(UPSERT)を使ってみた。」を読むと、カラムを省略すると一意規約違反となる組み合わせを含む・・・ということのようです。

3. 複数キー

 前項の最後の分、2024年11月11日に試してみました。  複数キーであれば、できるようです。  下記で作成したテーブル。

create table sample
	(index integer not null,
	 name text not null,
	 age integer not null);

alter table sample add constraint sample_key primary key(index, name);
 データとして、下記が存在している状態で。

 index |   name   | age
-------+----------+-----
     1 | hogehoge |  19
     2 | fugafuga |  20
     3 | piyopuyo |  21
 下記を実行すると。

insert into sample
	(index, name, age)
values
	(1, 'hogehoge', 23)
on conflict
	(index, name)
do update set age = 23;
 下記の状態になりました。

 index |   name   | age
-------+----------+-----
     2 | fugafuga |  20
     3 | piyopuyo |  21
     1 | hogehoge |  23
ハイスピードプラン