Upsert di PostgreSQL dengan ON CONFLICT
Gabungkan insert dan update dalam satu pernyataan untuk data yang mungkin sudah ada.
Masalah insert yang mungkin duplikat
Saat menyimpan data dari sumber luar, baris yang sama bisa terkirim lebih dari sekali. Melakukan SELECT untuk mengecek keberadaan data sebelum INSERT rentan terhadap race condition ketika dua proses berjalan bersamaan.
ON CONFLICT DO UPDATE
CREATE TABLE statistik_artikel (
artikel_id BIGINT PRIMARY KEY,
jumlah_dilihat BIGINT NOT NULL DEFAULT 0
);
INSERT INTO statistik_artikel (artikel_id, jumlah_dilihat)
VALUES (42, 1)
ON CONFLICT (artikel_id)
DO UPDATE SET jumlah_dilihat = statistik_artikel.jumlah_dilihat + 1;
Pernyataan di atas menambah baris baru jika artikel_id belum ada, atau menambah penghitung jika sudah ada, semuanya dalam satu operasi atomik.
ON CONFLICT DO NOTHING
Jika Anda hanya ingin mengabaikan baris yang sudah ada tanpa mengubah apa pun, gunakan DO NOTHING.
INSERT INTO email_terdaftar (email)
VALUES ('user@contoh.test')
ON CONFLICT (email) DO NOTHING;
Syarat memakai ON CONFLICT
Kolom yang disebut dalam ON CONFLICT harus memiliki UNIQUE constraint atau menjadi primary key. Tanpa itu, PostgreSQL tidak tahu kondisi mana yang dianggap konflik.
Membedakan dengan MERGE
PostgreSQL versi 15 ke atas juga mendukung pernyataan MERGE yang lebih fleksibel untuk kasus insert, update, dan delete sekaligus berdasarkan hasil join. ON CONFLICT tetap lebih ringkas untuk kasus upsert sederhana berbasis satu constraint unik.
Latihan
Ubah contoh statistik di atas agar juga menyimpan waktu terakhir dilihat, dan pastikan kolom tersebut ikut diperbarui saat konflik terjadi.
