概要
SQLite 3 でキーか重複するレコードがあれば更新、なければ新規挿入する方法。
具体的には テーブルにレコードを新規挿入しようとして Primary key や Unique が重複するレコードが既に存在していた場合、 新規挿入をやめて update に切り替えるための構文。
以下のような処理分岐をしてくれる。
重複するレコードがある場合 | 既存のレコードを「更新(update)」する、もしくは何もしない(nothing) |
重複するレコードがない場合 | そのまま 「新規挿入(insert)」 |
似たような処理にreplace
があるが、
replace
はレコード(行)を丸ごと入れ替える(delete/insert)のに対し、
upsertはカラムを指定してレコードを更新する。
公式
によると PostgreSQL の構文を利用しているとのこと。
Microsoft SQLServer や Oracle の「merge(マージ)」構文に近い使い方だが
mergeは重複の判定にUniqueカラム以外のものを指定できたりする。
実行例
「upsert」というコマンドがあるわけではなく、
on conflict
文を使い キーが重複した場合の処理を指定することができる。
on conflict
文は sqlite のバージョン3.24.0 から利用可能。
環境
- Windows 10
- sqlite3 (3.24.0) Command-Line Shell
id primary key autoincrement |
name not null |
quantity default 0 |
remark |
---|---|---|---|
1 | tomato | 100 | |
2 | potato | 120 | |
3 | pumpkin | 50 | (Comment...) |
重複していたら特定のカラムを更新する
以下は「id」カラムが重複していたら新規挿入をやめて、 別の値で「quantity」カラムを更新する例。
insert into
product (
id
, name
, quantity
, remark
)
values (
2
, 'potato'
, 150
, ''
)
on conflict(id)
do update
set
quantity = '200'
;
id primary key autoincrement |
name not null |
quantity default 0 |
remark |
---|---|---|---|
1 | tomato | 100 | |
2 | potato | 200 | |
3 | pumpkin | 50 | (Comment...) |
excluded テーブルを利用する
挿入しようとして、ユニークキーの重複エラーになった行は 「excluded」という一時テーブルに登録される。 update の際にこのexcludedを利用できる。
以下は「id」カラムが重複していたら 新規挿入をやめて、 挿入しようとした値で「quantity」カラムを更新する例
insert into
product (
id
, name
, quantity
, remark
)
values (
2
, 'potato'
, 150
, ''
)
on conflict(id)
do update
set
quantity = excluded.quantity
;
id primary key autoincrement |
name not null |
quantity default 0 |
remark |
---|---|---|---|
1 | tomato | 100 | |
2 | potato | 150 | |
3 | pumpkin | 50 | (Comment...) |
重複していなければ、新規登録される
以下は「id」カラムが重複していないので、 そのまま新規挿入される例。
insert into
product (
id
, name
, quantity
, remark
)
values (
4
, 'potato'
, 150
, ''
)
on conflict(id)
do update
set
quantity = '200'
;
id primary key autoincrement |
name not null |
quantity default 0 |
remark |
---|---|---|---|
1 | tomato | 100 | |
2 | potato | 120 | |
3 | pumpkin | 50 | (Comment...) |
4 | potato | 150 |
重複していた場合は何もしない、ということもできる
on conflict
の後にdo nothing
を記述すれば
重複していた場合は何もしない、という処理に出来る。
insert into
product (
id
, name
, quantity
, remark
)
values (
2
, 'potato'
, 150
, ''
)
on conflict(id)
do nothing
;
id primary key autoincrement |
name not null |
quantity default 0 |
remark |
---|---|---|---|
1 | tomato | 100 | |
2 | potato | 120 | |
3 | pumpkin | 50 | (Comment...) |
参考URL
-
SQLite 公式サイト(英語)
https://www.sqlite.org/index.html -
SQLite Query Language: upsert (英語)
公式のUPSERTに関するドキュメント
https://www.sqlite.org/lang_UPSERT.html
-
あさはか備忘録: SQLite3 Selectしたデータを他のテーブルに挿入
https://sfnovicenotes.blogspot.com/2019/07/sqlite3-select.html -
あさはか備忘録: SQLite3 Selectした結果でUpdateする (update from)
https://sfnovicenotes.blogspot.com/2020/10/sqlite3-selectupdate-update-from.html -
あさはか備忘録: SQLite3 SelectしたデータでUpdateする
https://sfnovicenotes.blogspot.com/2019/08/sqlite3-selectupdate.html