INSERT ON CONFLICT di PostgreSQL
Blog/Tutorial SQL/INSERT ON CONFLICT di PostgreSQL

INSERT ON CONFLICT di PostgreSQL

BimaBima
·25 Oktober 2026·11 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

INSERT ON CONFLICT di PostgreSQL adalah cara melakukan upsert: satu perintah yang insert baris baru, atau update baris lama kalau kunci uniknya bentrok. Kamu tulis INSERT biasa lalu tambahin ON CONFLICT (kolom) DO NOTHING buat skip, atau DO UPDATE SET buat memperbarui. Ini mencegah error duplicate key dan menghindari cek manual sebelum insert.

INSERT ON CONFLICT di PostgreSQL adalah cara insert baris baru atau update baris yang udah ada dalam satu perintah, tanpa bikin error duplikat. Orang sering nyebut ini upsert, gabungan dari update dan insert.

Tanpa fitur ini, kamu harus cek dulu apakah barisnya udah ada, baru pilih insert atau update. Dua langkah, dan rawan race condition kalau banyak proses jalan bareng.

Di artikel ini aku jelasin sintaks ON CONFLICT, beda DO NOTHING dan DO UPDATE, cara pakai kata kunci EXCLUDED, plus contoh nyata di data toko.

Apa itu INSERT ON CONFLICT?

INSERT ON CONFLICT adalah klausa PostgreSQL yang nentuin apa yang terjadi kalau baris yang mau kamu insert bentrok dengan constraint unik atau primary key. Kamu bisa suruh PostgreSQL diam aja (DO NOTHING) atau memperbarui baris yang udah ada (DO UPDATE). Fitur ini tersedia sejak PostgreSQL 9.5.

Bentrok terjadi waktu nilai yang kamu masukin nabrak primary key atau unique constraint yang udah dipakai baris lain. Normalnya, ini bikin query gagal dengan error duplicate key.

ON CONFLICT nangkep situasi itu dan kasih kamu jalan keluar, bukan error.

Gimana sintaks dasar ON CONFLICT?

Sintaksnya: tulis INSERT biasa, lalu tambahin ON CONFLICT diikuti target konflik (kolom unik atau nama constraint), lalu aksi DO NOTHING atau DO UPDATE SET. Target konflik ngasih tau PostgreSQL constraint mana yang dipantau.

Struktur umumnya begini:

INSERT INTO produk (kode, nama, stok)
VALUES ('P001', 'Beras 5kg', 40)
ON CONFLICT (kode)
DO NOTHING;

Kalau kode 'P001' udah ada, baris baru diabaikan dan nggak ada error. Kalau belum ada, baris masuk seperti INSERT biasa.

Kolom di dalam kurung setelah ON CONFLICT itu conflict target. Dia harus punya unique constraint atau primary key. Kalau nggak, PostgreSQL nggak tau konflik mana yang harus dipantau.

Apa beda DO NOTHING dan DO UPDATE?

DO NOTHING melewati baris yang bentrok tanpa mengubah apa pun. DO UPDATE memperbarui baris lama pakai nilai baru. Pilih DO NOTHING kalau cuma mau mencegah error duplikat, dan DO UPDATE kalau mau data yang lama ikut ter-refresh.

Ini contoh DO UPDATE buat nambah stok:

INSERT INTO produk (kode, nama, stok)
VALUES ('P001', 'Beras 5kg', 40)
ON CONFLICT (kode)
DO UPDATE SET stok = produk.stok + EXCLUDED.stok;

Kata kunci EXCLUDED nunjuk ke baris yang tadi mau diinsert tapi ditolak. Jadi EXCLUDED.stok = 40, nilai baru. Dan produk.stok = nilai yang udah ada di tabel. Hasilnya stok lama ditambah 40.

AksiKalau bentrokKapan dipakai
DO NOTHINGBaris diabaikanImport data yang mungkin ada duplikat, cukup skip
DO UPDATEBaris lama diperbaruiSinkronisasi stok, harga, atau status terbaru

Apa itu EXCLUDED dan kapan dipakai?

EXCLUDED adalah tabel virtual yang berisi nilai baris yang gagal diinsert karena bentrok. Kamu pakai di dalam DO UPDATE buat ngambil nilai yang tadi mau dimasukin. Ini yang bikin upsert bisa gabungin data lama dan baru.

Contoh: kamu mau update nama dan harga produk kalau kodenya udah ada, tapi tetap insert kalau belum.

INSERT INTO produk (kode, nama, harga)
VALUES ('P002', 'Minyak Goreng 1L', 18500)
ON CONFLICT (kode)
DO UPDATE SET
  nama = EXCLUDED.nama,
  harga = EXCLUDED.harga;

Tiap kolom di SET ngambil nilai baru lewat EXCLUDED. Kolom yang nggak disebut tetap kayak semula.

Contoh Kasus: Sinkronisasi Stok Toko Berkah

Toko Berkah tarik data stok dari kasir tiap malam, lalu masukin ke tabel inventaris di PostgreSQL. Masalahnya, produk yang sama muncul tiap hari. Insert biasa langsung error di produk yang udah ada.

Struktur tabelnya: inventaris (kode TEXT PRIMARY KEY, nama TEXT, stok INT, update_terakhir DATE).

Query upsert yang dipakai:

INSERT INTO inventaris (kode, nama, stok, update_terakhir)
VALUES
  ('BRS01', 'Beras 5kg', 42, '2026-10-25'),
  ('MYK01', 'Minyak 1L', 60, '2026-10-25'),
  ('GLA01', 'Gula 1kg', 35, '2026-10-25')
ON CONFLICT (kode)
DO UPDATE SET
  stok = EXCLUDED.stok,
  update_terakhir = EXCLUDED.update_terakhir;

Sebelum pakai ON CONFLICT, tim toko jalanin dua query: SELECT buat cek keberadaan tiap kode, lalu INSERT atau UPDATE terpisah. Buat 320 produk, itu ratusan roundtrip ke database.

Dengan satu upsert batch, semua 320 baris beres dalam satu perintah. Dari yang aku ukur di kasus sejenis, jumlah statement yang dikirim turun dari 640 (cek plus tulis) jadi 1. Beban ke database jauh lebih ringan.

Kalau tabel inventaris kamu sering di-query buat laporan, pastikan indexnya bener. Cek panduan composite index di SQL biar filter tanggal dan kode tetap ngebut.

Update bersyarat dengan WHERE

Kamu bisa tambahin WHERE di belakang DO UPDATE biar update cuma jalan kalau kondisi tertentu terpenuhi. Ini berguna buat mencegah update yang nggak perlu.

INSERT INTO inventaris (kode, nama, stok, update_terakhir)
VALUES ('BRS01', 'Beras 5kg', 42, '2026-10-25')
ON CONFLICT (kode)
DO UPDATE SET
  stok = EXCLUDED.stok,
  update_terakhir = EXCLUDED.update_terakhir
WHERE inventaris.update_terakhir < EXCLUDED.update_terakhir;

Update cuma terjadi kalau tanggal di tabel lebih lama dari data baru. Data yang lebih tua nggak nimpa data yang lebih baru.

Kesalahan Umum saat Pakai ON CONFLICT

  • Conflict target tanpa constraint. Kolom di ON CONFLICT (kolom) harus punya unique constraint atau primary key. Kalau nggak, PostgreSQL kasih error "no unique or exclusion constraint matching".
  • Salah nyebut nama tabel di DO UPDATE. Buat baca nilai baru pakai EXCLUDED, buat baca nilai lama pakai nama tabel. Ketuker bikin hasil salah.
  • Lupa ON CONFLICT di batch besar. Satu duplikat aja bikin seluruh batch INSERT gagal dan di-rollback.
  • Pakai DO UPDATE waktu cuma butuh skip. DO UPDATE nulis ulang baris dan naikin beban tulis. Kalau cuma mau hindari error, DO NOTHING lebih hemat.

FAQ

Apakah INSERT ON CONFLICT sama dengan MERGE?

Mirip tapi nggak identik. ON CONFLICT khusus buat kasus bentrok constraint unik saat insert, dan sintaksnya ringkas buat upsert. MERGE, yang masuk di PostgreSQL 15, lebih umum dan bisa nangani insert, update, sekaligus delete berdasarkan kondisi join. Buat upsert sederhana, ON CONFLICT lebih pendek dan gampang dibaca.

Apa yang terjadi kalau ada dua unique constraint?

Kamu harus milih satu conflict target. ON CONFLICT (kode) cuma mantau constraint pada kolom kode. Kalau baris juga bentrok di constraint lain yang nggak kamu sebut, query tetap error. Kalau mau nangani konflik apa pun tanpa nyebut kolom, pakai ON CONFLICT DO NOTHING tanpa target, tapi ini cuma valid buat DO NOTHING, bukan DO UPDATE.

Bisakah ON CONFLICT dipakai buat banyak baris sekaligus?

Bisa. Kamu tulis INSERT dengan banyak baris di VALUES, lalu satu klausa ON CONFLICT berlaku ke semuanya. Tiap baris dicek terhadap constraint, dan yang bentrok ditangani sesuai aksi yang kamu pilih. Ini cara efisien buat import batch, karena semua baris beres dalam satu perintah.

Apakah EXCLUDED wajib dipakai di DO UPDATE?

Nggak wajib, tapi biasanya kamu butuh. EXCLUDED ngasih akses ke nilai baru yang tadi mau diinsert. Tanpa EXCLUDED, kamu cuma bisa set kolom ke nilai tetap atau hasil hitung dari kolom lama. Kalau tujuannya nyalin data baru ke baris lama, EXCLUDED jalan tercepat.

Apakah ON CONFLICT aman dari race condition?

Ya, jauh lebih aman dari pola cek-dulu-baru-tulis. ON CONFLICT ditangani di level satu perintah oleh PostgreSQL, jadi dua proses yang insert baris sama secara bersamaan nggak akan bikin duplikat atau error tak terduga. Ini salah satu alasan utama upsert satu perintah lebih dipilih ketimbang dua query terpisah.

Penutup

ON CONFLICT ngerapihin logika upsert yang tadinya butuh dua langkah. Yang perlu kamu inget:

  • Conflict target harus punya unique constraint atau primary key.
  • DO NOTHING buat skip, DO UPDATE buat memperbarui pakai EXCLUDED.
  • Tambahin WHERE kalau update perlu bersyarat.

Mau latihan nulis query upsert dan yang lain sampai lancar? Praktek langsung di NgulikSQL. Lanjut juga baca cara menghitung DAU dan MAU dengan SQL buat perkuat skill query harianmu.

Referensi resmi: dokumentasi INSERT PostgreSQL.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel terkait

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain
Tutorial SQL
14 November 2026•8 menit baca

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain

Semi join ngambil baris yang punya pasangan di tabel lain, anti join ngambil yang nggak punya. Keduanya filter, bukan gabung kolom. Ini cara nulisnya di SQL pakai EXISTS dan NOT EXISTS.

BimaBima
Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom
Tutorial SQL
2 November 2026•11 menit baca

Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom

Crosstab di PostgreSQL mivot data dari format panjang (baris) jadi format lebar (kolom), mirip pivot table Excel. Butuh extension tablefunc, dan ada alternatif pakai CASE atau FILTER kalau kolomnya tetap.

BimaBima
7 Antipattern SQL yang Bikin Query Lambat
Tutorial SQL
18 Oktober 2026•8 menit baca

7 Antipattern SQL yang Bikin Query Lambat

Tujuh pola SQL yang diam-diam bikin query lambat, dari SELECT bintang, fungsi di kolom filter, sampai OFFSET besar. Plus cara benerin tiap satunya.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore