Constraint adalah aturan yang kamu pasang di kolom tabel, dan database sendiri yang menolak data yang melanggarnya. Bayangin petugas loket yang memeriksa formulir pendaftaran: kolom bertanda wajib gak boleh kosong, email yang sudah terdaftar ditolak, gaji gak boleh nol, dan kolom yang dikosongkan diisi nilai bawaan. Aplikasimu boleh ikut mengecek, tapi constraint adalah penjaga terakhir: data yang melanggar gak akan pernah masuk tabel, dari mana pun datangnya.
🧪 Tebakan cepat: tabel
absensipunyaFOREIGN KEYke tabelemployees. Kamu mencatat absen untuk karyawan id 99, padahal karyawan itu gak ada. Di SQLite, apa yang terjadi: error, atau masuk begitu saja? Tebak dulu, jawabannya ada di bagian "FOREIGN KEY: harus menunjuk ke baris yang ada".
Tabel dengan aturan
Ini tabel employees dari latihan. Aturannya ditulis sesudah tipe data tiap kolom:
CREATE TABLE employees (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
salary REAL CHECK (salary > 0),
department TEXT DEFAULT 'General'
);
id INTEGER PRIMARY KEY AUTOINCREMENT: nomor unik tiap baris, diisi otomatis 1, 2, 3, dan seterusnya.name TEXT NOT NULL: NOT NULL artinya wajib diisi.NULLadalah tanda "gak ada isinya" di SQL.email TEXT UNIQUE NOT NULL: UNIQUE artinya gak boleh ada dua baris dengan email yang sama. DitambahNOT NULL, jadi juga wajib diisi.salary REAL CHECK (salary > 0): CHECK adalah aturan buatanmu sendiri. Kondisi di dalam kurung harus benar untuk setiap baris.department TEXT DEFAULT 'General': DEFAULT adalah isian bawaan. KalauINSERTgak menyebut kolom ini, isinya otomatis'General'.
Satu kolom boleh punya beberapa aturan sekaligus, seperti email di atas.
Apa yang terjadi kalau aturannya dilanggar
Budi sudah ada di tabel dengan email [email protected]. Ini empat INSERT berikutnya, dengan jawaban SQLite apa adanya:
INSERT INTO employees (name, email, salary) VALUES ('Siti', '[email protected]', 9000000);
-- masuk, department-nya otomatis 'General'
INSERT INTO employees (name, email, salary) VALUES ('Budi Dua', '[email protected]', 7000000);
-- UNIQUE constraint failed: employees.email
INSERT INTO employees (email, salary) VALUES ('[email protected]', 5000000);
-- NOT NULL constraint failed: employees.name
INSERT INTO employees (name, email, salary) VALUES ('Andi', '[email protected]', 0);
-- CHECK constraint failed: salary > 0
- Pesan error-nya selalu menyebut aturan yang dilanggar dan kolomnya, jadi baca pesan itu dulu sebelum menebak-nebak.
INSERTyang ditolak batal seluruhnya. Gak ada baris setengah jadi yang tertinggal.INSERTSiti gak menyebutdepartment, jadiDEFAULTmengisinya dengan'General'.
Satu hal yang sering bikin kaget: CHECK lolos kalau nilainya NULL. INSERT tanpa salary tetap masuk, karena NULL > 0 hasilnya bukan "salah", tapi "gak tahu". Kalau gaji wajib ada, tambahkan NOT NULL juga.
FOREIGN KEY: harus menunjuk ke baris yang ada
FOREIGN KEY memastikan nilai di satu kolom benar-benar ada di tabel lain. Tabel absensi mencatat kehadiran, dan employee_id-nya harus menunjuk ke karyawan yang ada:
PRAGMA foreign_keys = ON;
CREATE TABLE absensi (
id INTEGER PRIMARY KEY,
employee_id INTEGER NOT NULL REFERENCES employees(id),
tanggal TEXT NOT NULL
);
INSERT INTO absensi (employee_id, tanggal) VALUES (99, '2026-10-08');
-- FOREIGN KEY constraint failed
REFERENCES employees(id)artinya isiemployee_idharus ada di kolomidtabelemployees.PRAGMA foreign_keys = ON;menyalakan pemeriksaan foreign key. Di SQLite, pemeriksaan ini mati secara bawaan, dan harus dinyalakan setiap kali membuka koneksi. Tanpa baris itu, absen untuk karyawan 99 masuk begitu saja, tanpa error. Itu jawaban tebakannya.- Kebalikannya juga dijaga: selama Budi punya absen,
DELETEBudi ditolak dengan pesan yang sama. Kalau maunya absennya ikut terhapus, tulisREFERENCES employees(id) ON DELETE CASCADE.
📌 Beda di MySQL dan PostgreSQL
MySQL (dengan tabel InnoDB, bawaannya) dan PostgreSQL selalu memeriksa FOREIGN KEY, gak perlu PRAGMA. CHECK baru benar-benar dijalankan MySQL sejak versi 8.0.16, versi lebih lama menerimanya lalu diam-diam mengabaikannya. Panjang VARCHAR(255) juga beda: MySQL dan PostgreSQL menolak teks yang lebih panjang, sedangkan SQLite menyimpannya saja. NOT NULL, UNIQUE dan DEFAULT bekerja sama di ketiganya.
⚠️ Jebakan yang sering ketemu
- Mengira aplikasi sudah cukup mengecek. Data bisa masuk dari banyak jalan: form lain, script import, atau perintah SQL langsung. Constraint menjaga semuanya.
UNIQUEdi kolom yang salah. Latihannya mengecek tabelnya punya tepat satu aturanUNIQUE, diemail. Nama orang boleh kembar.- Lupa
NOT NULLdi salah satu kolom.namedanemailsama-sama wajib, dua-duanya dicek. CHECKyang lupa ditulis. TanpaCHECK (salary > 0), gaji 0 atau minus masuk tanpa protes.- Lupa
PRAGMA foreign_keys = ONdi SQLite. Foreign key-nya ada di definisi tabel, tapi gak ada yang memeriksanya.
TL;DR: Constraint adalah aturan di kolom yang dijaga database sendiri. NOT NULL wajib diisi, UNIQUE gak boleh kembar, CHECK (kondisi) harus benar, DEFAULT nilai mengisi kolom yang gak disebut, dan FOREIGN KEY ... REFERENCES memastikan nilainya ada di tabel lain. Pelanggaran membatalkan seluruh INSERT dengan pesan yang menyebut aturan dan kolomnya. CHECK lolos untuk NULL, dan di SQLite foreign key baru diperiksa setelah PRAGMA foreign_keys = ON.