TL;DR
Constraint SQL adalah aturan yang dipasang di kolom atau tabel supaya database nolak data yang gak sesuai sebelum data itu kesimpan. Empat yang paling sering dipakai: NOT NULL bikin kolom gak boleh kosong, UNIQUE bikin nilainya gak boleh kembar, CHECK ngecek syarat logika kayak harga harus di atas nol, dan DEFAULT ngisi nilai otomatis kalau kolomnya dikosongin. Constraint dijaga sama database, jadi tetap jalan walau datanya masuk lewat aplikasi lain.
Constraint adalah aturan yang dipasang di kolom atau tabel supaya database nolak data yang gak sesuai. Data sampah ditahan di pintu masuk, bukan dibersihin tiga bulan kemudian.
Empat yang paling sering dipakai: NOT NULL, UNIQUE, CHECK, dan DEFAULT.
Bedanya sama validasi di aplikasi: constraint dijaga database. Data yang masuk lewat impor CSV, skrip Python, atau tim lain yang gak tau aturanmu. Semuanya kena.
Constraint adalah aturan yang nempel di struktur tabel dan dicek otomatis tiap kali ada data masuk atau diubah. Kalau datanya melanggar, database nolak seluruh baris itu dan ngasih pesan error. Gak ada yang setengah kesimpan.
Ini contoh tabel produk dengan empat constraint terpasang sekaligus:
CREATE TABLE produk (
id_produk INT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
sku VARCHAR(30) UNIQUE NOT NULL,
kategori VARCHAR(50) NOT NULL DEFAULT 'Lainnya',
harga DECIMAL(12,2) NOT NULL CHECK (harga > 0),
stok INT NOT NULL DEFAULT 0 CHECK (stok >= 0)
);
Satu tabel, enam kolom, enam aturan. Sekarang bedah satu-satu.
NOT NULL bikin kolom gak boleh kosong, nggak ada pengecualian.
INSERT INTO produk (id_produk, nama, sku, harga) VALUES
(5, NULL, 'SNK-002', 9000.00);
-- ERROR: null value in column "nama" violates not-null constraint
Kelihatan sepele. Tapi kolom yang boleh kosong bikin masalah berantai di query.
Contohnya: kalau kolom harga boleh NULL, maka SUM(harga) diam-diam ngelewatin baris itu. Total penjualanmu kurang, dan gak ada satu pun error yang muncul.
Aturan praktis: kasih NOT NULL ke semua kolom yang secara bisnis wajib ada isinya. Kalau kamu ragu "boleh kosong gak ya?", jawabannya biasanya gak boleh.
Cara NULL bikin agregasi meleset dijelasin lebih lengkap di halaman glosarium NULL.
UNIQUE bikin nilai di satu kolom gak boleh kembar.
INSERT INTO produk (id_produk, nama, sku, harga) VALUES
(6, 'Kopi Sachet Baru', 'MIN-001', 3000.00);
-- ERROR: duplicate key value violates unique constraint
SKU MIN-001 udah dipakai produk lain. Ditolak.
| Sifat | PRIMARY KEY | UNIQUE |
|---|---|---|
| Boleh kembar | Nggak | Nggak |
| Boleh kosong | Nggak | Boleh |
| Jumlah per tabel | Cuma 1 | Boleh banyak |
Jadi: id_produk jadi primary key, sementara sku dan email masing-masing bisa dikasih UNIQUE tanpa bentrok.
Perbandingan lengkapnya ada di artikel primary key dan foreign key.
CHECK ngecek syarat logika. Kalau syaratnya gak kepenuhi, barisnya ditolak.
harga DECIMAL(12,2) NOT NULL CHECK (harga > 0)
Coba masukin produk dengan harga 0:
INSERT INTO produk (id_produk, nama, sku, harga) VALUES
(7, 'Sampel Gratis', 'SMP-001', 0.00);
-- ERROR: new row violates check constraint
Ditolak. Kalau kamu memang butuh nyimpen produk gratis, ganti aturannya jadi CHECK (harga >= 0), tapi itu keputusan bisnis, bukan kelalaian.
Ini yang paling sering kepake:
status VARCHAR(20) NOT NULL DEFAULT 'aktif'
CHECK (status IN ('aktif', 'nonaktif', 'habis'))
Sekarang kolom status cuma bisa diisi tiga nilai itu. Ada yang nulis "Aktif" pakai huruf besar? Ditolak. "pending"? Ditolak.
Tanpa CHECK, kolom status di database nyata biasanya berakhir kayak gini: "aktif", "Aktif", "AKTIF", "active", "1", dan "". Lima variasi buat satu makna, dan setiap laporan yang ngelompokin status jadi salah.
CREATE TABLE promo (
id_promo INT PRIMARY KEY,
kode VARCHAR(20) UNIQUE NOT NULL,
mulai DATE NOT NULL,
selesai DATE NOT NULL,
CONSTRAINT ck_periode_promo CHECK (selesai >= mulai)
);
Promo yang selesai sebelum dimulai? Gak bisa masuk. Aturan ini ditaruh di level tabel karena nyentuh dua kolom sekaligus.
DEFAULT ngisi nilai otomatis kalau kolomnya gak disebut waktu insert.
INSERT INTO produk (id_produk, nama, sku, harga) VALUES
(4, 'Gula Pasir 1kg', 'SMB-002', 16000.00);
-- kategori otomatis jadi 'Lainnya', stok jadi 0, status jadi 'aktif'
Yang paling sering dipakai: kolom timestamp.
dibuat_pada TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
Tiap baris baru otomatis dapat cap waktu. Gak perlu diisi manual, gak bisa lupa.
DEFAULT cuma jalan kalau kolomnya sama sekali gak disebut di INSERT.
-- kategori kena DEFAULT 'Lainnya'
INSERT INTO produk (id_produk, nama, sku, harga)
VALUES (10, 'Teh Celup', 'MIN-003', 8000);
-- kategori jadi NULL, DEFAULT gak jalan
INSERT INTO produk (id_produk, nama, sku, kategori, harga)
VALUES (11, 'Teh Tarik', 'MIN-004', NULL, 9000);
Yang kedua bakal ditolak, karena kolom kategori juga punya NOT NULL.
Ini yang bikin impor CSV sering gagal massal: sel kosong di CSV kekirim sebagai NULL eksplisit, bukan sebagai "gak disebut".
Waktu aku ngecek tabel produk di dataset toko_berkah (1.847 baris, dikumpulin dari 3 sistem berbeda selama 2 tahun), kolom status gak punya CHECK constraint sama sekali.
Isinya:
| Nilai | Jumlah baris |
|---|---|
| aktif | 1.203 |
| Aktif | 287 |
| AKTIF | 94 |
| active | 41 |
| nonaktif | 178 |
| (kosong) | 44 |
Query WHERE status = 'aktif' ngeluarin 1.203 baris. Padahal produk aktif yang sebenernya ada 1.625, selisih 422 baris, atau 26%.
Laporan ketersediaan produk yang dipakai tim purchasing selama setahun bilang stok aktifnya 1.203. Mereka pesan ulang berdasarkan angka itu.
Satu baris CHECK constraint waktu tabelnya pertama dibikin. 422 baris salah klasifikasi itu gak pernah ada.
Pakai ALTER TABLE:
ALTER TABLE produk
ADD CONSTRAINT ck_harga_wajar CHECK (harga <= 10000000);
Tapi ada satu langkah yang wajib duluan: cek data lama.
Database bakal nolak ALTER TABLE kalau ada satu aja baris lama yang melanggar aturannya. Dan pesan errornya jarang nunjukin baris mana yang bermasalah.
Cari dulu pakai SELECT:
SELECT id_produk, nama, harga
FROM produk
WHERE harga <= 0 OR harga IS NULL;
Bersihin baris yang keluar, baru pasang constraintnya. Urutannya jangan dibalik.
Form aplikasi kamu emang nolak harga minus. Tapi impor CSV nggak. Skrip cron nggak. Tim lain yang akses database langsung juga nggak.
Constraint di database jadi lapisan terakhir yang gak bisa dilewatin siapa pun.
Udah dibahas di atas. Sel kosong di CSV biasanya kekirim sebagai NULL eksplisit, dan DEFAULT gak jalan buat itu.
Kalau kamu nulis CHECK (harga > 0) tanpa CONSTRAINT nama_aturan, database bikin nama acak kayak produk_harga_check1.
Setahun kemudian waktu kamu mau hapus atau ubah aturannya, kamu harus nyari dulu namanya. Kasih nama yang jelas sejak awal.
CHECK (harga >= 1000) kedengeran masuk akal, sampai ada produk promo seharga 500. Sekarang tim ops gak bisa masukin produknya, dan kamu harus ALTER TABLE di jam sibuk.
Constraint buat nahan data yang pasti salah, bukan data yang jarang terjadi.
Email dan nomor HP bisa berubah, dan bisa dipakai ulang. UNIQUE di situ kadang bikin masalah waktu pelanggan lama daftar ulang. Pikirin dulu skenario perubahannya.
Constraint adalah aturan yang dipasang di kolom atau tabel supaya database nolak data yang gak sesuai sebelum data itu kesimpan. Bedanya sama validasi di aplikasi: constraint dijaga database, jadi tetap jalan walau datanya masuk lewat impor CSV atau skrip lain.
Dua-duanya bikin nilai gak boleh kembar. Bedanya: primary key gak boleh kosong dan cuma boleh ada satu per tabel. UNIQUE boleh kosong dan boleh dipasang di banyak kolom sekaligus. Contohnya id_produk jadi primary key, sementara kolom SKU dan email masing-masing bisa dikasih UNIQUE.
Pakai CHECK kalau kamu punya aturan logika yang harus selalu benar, misalnya harga harus di atas nol atau tanggal selesai gak boleh sebelum tanggal mulai. CHECK juga bisa batasin isi kolom ke daftar tertentu pakai IN, ini jauh lebih aman dari cuma ngandelin dropdown di aplikasi.
Nggak. DEFAULT cuma jalan kalau kolomnya sama sekali gak disebut di INSERT. Kalau kamu tulis NULL secara eksplisit, database nyimpen NULL, atau nolak baris itu kalau kolomnya juga NOT NULL. Ini yang paling sering bikin impor CSV gagal massal.
Bisa pakai ALTER TABLE ADD CONSTRAINT, tapi database bakal nolak kalau ada data lama yang melanggar aturannya. Cek dulu pakai SELECT, bersihin, baru pasang. Daftar lengkap jenis constraint bisa kamu baca di dokumentasi constraint PostgreSQL.
Constraint yang paling worth dipasang duluan:
ALTER TABLE ADD CONSTRAINT, cek data lama pakai SELECT dulu.Coba jalanin query cek nilai unik di kolom status database kamu sekarang. Kalau keluar lebih dari yang kamu harapkan, kamu baru nemu sumber laporan yang selama ini meleset.
Mau ngerti relasi antar tabel dulu? Baca panduan primary key dan foreign key. Buat yang mau lancar nyaring data, ada panduan WHERE di SQL lengkap.
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.