TL;DR
INSERT di SQL dipakai buat nambah baris baru ke sebuah tabel, dengan sintaks dasar INSERT INTO nama_tabel (kolom) VALUES (nilai). Kamu bisa masukin banyak baris sekaligus dengan misahin tiap set VALUES pakai koma, dan ini jauh lebih cepat daripada ngirim query INSERT satu per satu. Buat nyalin data dari tabel lain, pakai bentuk INSERT INTO ... SELECT tanpa klausa VALUES.
INSERT nambahin baris baru ke tabel. Sintaks dasarnya INSERT INTO nama_tabel (kolom) VALUES (nilai).
Perintah ini gampang. Yang bikin orang kena masalah bukan sintaksnya, tapi hal-hal di sekitarnya: primary key bentrok, urutan kolom ketuker, atau 50.000 baris yang dikirim satu-satu sampai kelar sejam.
Aku bahas semuanya di sini, dari yang paling dasar sampai upsert.
INSERT adalah perintah SQL yang nambahin satu atau lebih baris baru ke sebuah tabel. Dia termasuk kategori DML, perintah yang ngubah isi data, bukan struktur tabelnya.
INSERT INTO pelanggan (nama, email, kota)
VALUES ('Rina Wijaya', 'rina@contoh.id', 'Jakarta');
Tiga bagian:
INSERT INTO pelanggan: tabel tujuannya.(nama, email, kota): kolom yang mau diisi.VALUES (...): nilainya, urutannya harus nyocokin daftar kolom di atas.Kolom yang gak kamu sebut bakal keisi otomatis: pakai DEFAULT kalau ada, atau NULL kalau kolomnya ngizinin.
Kamu bisa nulis tanpa nyebut kolom:
INSERT INTO pelanggan VALUES (1, 'Rina', 'rina@contoh.id', 'Jakarta', '2026-02-01', TRUE);
Jangan. Query ini bergantung ke urutan kolom di tabel. Begitu ada developer lain nambah kolom no_hp di tengah, query kamu rusak. Atau lebih parah, masukin email ke kolom kota tanpa satu pun pesan error.
Sebut kolomnya. Selalu.
Pisahin tiap set VALUES pakai koma:
INSERT INTO pelanggan (nama, email, kota) VALUES
('Budi Santoso', 'budi@contoh.id', 'Bandung'),
('Sari Dewi', 'sari@contoh.id', 'Surabaya'),
('Andi Pratama', 'andi@contoh.id', 'Jakarta'),
('Maya Kusuma', 'maya@contoh.id', 'Semarang'),
('Doni Firmansyah', 'doni@contoh.id', 'Bandung');
Satu query, lima baris masuk. Ini bukan cuma soal hemat ketikan.
Tiap query yang dikirim ke database punya biaya: overhead jaringan plus transaksi. Waktu aku tes masukin 10.000 baris ke PostgreSQL lokal, hasilnya begini:
| Metode | Waktu | Catatan |
|---|---|---|
| 10.000 query INSERT terpisah | ~38 detik | Overhead per query numpuk |
| 10 query, masing-masing 1.000 baris | ~1,2 detik | Sweet spot buat kebanyakan kasus |
| Perintah COPY dari file CSV | ~0,3 detik | Buat data massal beneran |
Batch 500-1.000 baris per query itu titik yang enak. Lebih dari 10.000 baris per query, query-nya jadi kegedean dan malah kena limit ukuran paket.
Buat data di atas 100.000 baris, lupain INSERT. Pakai COPY di PostgreSQL atau LOAD DATA INFILE di MySQL.
Pakai INSERT INTO ... SELECT. Perhatiin: gak ada kata VALUES sama sekali.
INSERT INTO pelanggan_vip (pelanggan_id, nama, total_belanja)
SELECT p.pelanggan_id,
p.nama,
SUM(o.total) AS total_belanja
FROM pelanggan p
JOIN pesanan o ON o.pelanggan_id = p.pelanggan_id
GROUP BY p.pelanggan_id, p.nama
HAVING SUM(o.total) >= 200000;
Query ini ngambil semua pelanggan yang total belanjanya minimal Rp 200.000, lalu masukin ke tabel VIP.
Di dataset ngulikdata, dari 6 pelanggan cuma 2 yang lolos: Rina (Rp 305.000) dan Sari (Rp 145.000 gak lolos, jadi cuma Rina dan Budi). Ini pola yang aku pakai tiap bulan buat refresh tabel segmentasi.
Jumlah dan urutan kolom di SELECT harus nyocokin daftar kolom tujuan. Kalau ketuker, database bisa error. Atau lebih jahat lagi, masukin nilai ke kolom yang salah kalau tipenya kebetulan cocok.
Kalau bagian GROUP BY dan HAVING masih samar, cek dulu panduan GROUP BY dan HAVING.
Di PostgreSQL, pakai RETURNING:
INSERT INTO pelanggan (nama, email, kota)
VALUES ('Tia Rahmawati', 'tia@contoh.id', 'Yogyakarta')
RETURNING pelanggan_id, nama;
Query-nya balikin baris hasil insert lengkap sama ID yang di-generate otomatis. Berguna banget kalau kamu langsung mau masukin pesanan buat pelanggan yang baru aja dibuat.
Di MySQL, gak ada RETURNING. Pakai SELECT LAST_INSERT_ID() setelah INSERT. Di SQL Server, pakai klausa OUTPUT.
Sintaks lengkap INSERT ada di dokumentasi resmi PostgreSQL.
Ini kasus yang sering muncul di proses sinkronisasi data harian.
INSERT INTO pelanggan (nama, email, kota)
VALUES ('Rina Wijaya', 'rina@contoh.id', 'Depok')
ON CONFLICT (email)
DO UPDATE SET kota = EXCLUDED.kota;
EXCLUDED itu baris yang tadi mau dimasukin. Jadi kalau email-nya udah ada, kotanya di-update jadi Depok.
INSERT INTO pelanggan (nama, email, kota)
VALUES ('Rina Duplikat', 'rina@contoh.id', 'Bogor')
ON CONFLICT (email) DO NOTHING;
Barisnya dilewati tanpa error. Cocok buat import data yang mungkin ngandung duplikat.
Di MySQL, sintaksnya INSERT ... ON DUPLICATE KEY UPDATE. Konsepnya sama.
Bungkus pakai transaksi:
BEGIN;
INSERT INTO pesanan (pelanggan_id, produk, qty, total, tanggal)
VALUES (2, 'Minyak Kelapa 250ml', 2, 130000, '2026-02-12');
-- cek dulu hasilnya
SELECT * FROM pesanan ORDER BY pesanan_id DESC LIMIT 1;
COMMIT; -- kalau bener
-- ROLLBACK; -- kalau salah
Selama belum COMMIT, semuanya masih bisa dibatalin. Ini kebiasaan yang nyelametin aku berkali-kali.
Aturan pegangan: kalau query-nya nyentuh tabel produksi, mulai dengan BEGIN. Ketik COMMIT belakangan, setelah kamu lihat hasilnya bener.
Pesannya: duplicate key value violates unique constraint. Artinya nilai yang kamu masukin bentrok sama primary key atau kolom UNIQUE.
Kalau memang mau ngubah baris lama, pakai ON CONFLICT DO UPDATE. Kalau cukup dilewatin, pakai DO NOTHING.
INSERT INTO pelanggan (pelanggan_id, nama, email)
VALUES (1, 'Rina', 'rina@contoh.id'); -- jangan
Kolom SERIAL punya sequence sendiri. Kalau kamu isi manual, sequence-nya gak ikut naik, dan beberapa insert berikutnya bakal bentrok. Biarin database yang ngisi.
Masukin pesanan dengan pelanggan_id = 99 padahal pelanggan 99 gak ada? Error foreign key violation.
Urutannya penting: insert pelanggan dulu, baru pesanannya.
Pakai format ISO: '2026-02-12'. Format '12/02/2026' bisa kebaca beda tergantung setelan database.
Kalau kolom email punya constraint NOT NULL dan kamu gak nyebut kolom itu, insert-nya gagal. Cek struktur tabel dulu pakai \d pelanggan di psql.
Di SQL standar, string pakai kutip tunggal: 'Rina'. Kutip ganda itu buat nama kolom atau tabel. MySQL agak longgar soal ini, PostgreSQL nggak.
VALUES buat nilai yang kamu ketik langsung. SELECT buat nyalin dari tabel lain. Bentuk ini gak pakai kata VALUES sama sekali.
Nilainya bentrok sama primary key atau kolom UNIQUE yang udah ada. Pakai ON CONFLICT DO UPDATE atau DO NOTHING.
Multi-row jauh lebih cepat. Di tes 10.000 baris, selisihnya 38 detik vs 1,2 detik.
Perlu. Tanpa itu, query kamu bergantung ke urutan kolom di tabel, dan bakal rusak diam-diam waktu skema berubah.
Kalau jalan di dalam transaksi, ketik ROLLBACK. Kalau udah COMMIT, satu-satunya cara ya DELETE manual.
Sebut nama kolom eksplisit. Gabung baris jadi multi-row kalau datanya banyak. Bungkus pakai BEGIN kalau nyentuh produksi.
Tiga kebiasaan itu yang bedain INSERT yang aman dan INSERT yang bikin kamu begadang.
Copy blok SQL di artikel ini ke database latihanmu, jalanin nomor 1 sampai 4 berurutan, lalu coba sengaja bikin duplicate key error di nomor 7. Ngeliat error-nya sekali bikin kamu inget selamanya.
Lanjut: UPDATE SQL buat ngubah data yang udah masuk, atau referensi perintah INSERT buat sintaks per database.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Analisa per kuartal, hari kerja, atau musim jadi ribet kalau tiap query ngitung ulang atribut tanggal. Tabel kalender nyimpen semua atribut itu sekali, biar tinggal di-JOIN.
Laporan penjualan harian sering bolong di hari tanpa transaksi. Ini cara bikin deret tanggal lengkap di SQL biar tiap hari muncul, walau nilainya nol.
Struktur organisasi tersimpan sebagai kolom id_atasan yang saling nunjuk. Ini cara narik rantai jabatan, hitung total bawahan, dan span of control cuma pakai SQL.