Constraint

Menjaga keabsahan data dengan PRIMARY KEY, NOT NULL, UNIQUE, dan CHECK.

Daftar isi

Constraint adalah aturan yang menyertai definisi kolom atau tabel untuk membatasi nilai yang boleh disimpan. Tanpa constraint, keabsahan data sepenuhnya bergantung pada kedisiplinan setiap program yang menulis ke basis data. Topik ini membahas PRIMARY KEY, NOT NULL, UNIQUE, CHECK, dan DEFAULT, beserta pesan error nyata yang muncul ketika masing-masing aturan dilanggar.

PRIMARY KEY sebagai alias rowid#

Setiap tabel biasa di SQLite memiliki kolom tersembunyi bernama rowid, yaitu bilangan bulat unik yang menandai setiap baris. Kolom yang dideklarasikan INTEGER PRIMARY KEY menjadi alias rowid, sehingga membaca kolom itu sama dengan membaca rowidnya. Blok berikut membuat tabel kategori, memasukkan tiga baris tanpa nilai id maupun dengan id NULL, lalu menampilkan keduanya berdampingan.

sql Contoh: INTEGER PRIMARY KEY sebagai alias rowid
CREATE TABLE kategori (
    id   INTEGER PRIMARY KEY,
    nama TEXT NOT NULL
);

INSERT INTO kategori (nama) VALUES ('Sains'), ('Sastra');

INSERT INTO kategori (id, nama) VALUES (NULL, 'Sejarah');

SELECT id, rowid, nama FROM kategori;
text Keluaran
1|1|Sains
2|2|Sastra
3|3|Sejarah

Keluaran menunjukkan bahwa id dan rowid bernilai sama pada setiap baris. SQLite mengisi nilai tersebut secara otomatis dengan bilangan yang lebih besar daripada nilai rowid terbesar yang sedang dipakai, sehingga program tidak perlu menomori baris secara manual. Pengenal bertipe ini menjadi titik rujukan yang stabil bagi tabel lain, misalnya tabel peminjaman yang menyimpan id buku. Alias tersebut juga cepat, karena pencarian berdasarkan rowid adalah pencarian langsung pada struktur penyimpanan tabel.

Nilai rowid sebuah tabel biasa dapat berubah ketika tabelnya dibangun ulang, tetapi nilai kolom alias tidak, karena kolom itu tersimpan sebagai kolom biasa pada berkas basis data. Deklarasi INTEGER PRIMARY KEY dengan demikian menjadi cara yang sah untuk menetapkan pengenal permanen. Kedua sifat tersebut menjadikannya pilihan bawaan untuk kolom id pada hampir semua skema SQLite.

NOT NULL dan DEFAULT#

Constraint NOT NULL menolak NULL pada kolomnya, baik saat INSERT maupun saat UPDATE. Pelanggaran menghentikan pernyataan yang bersangkutan dan menghasilkan pesan error yang menyebut tabel serta kolomnya. Blok berikut mencoba memasukkan anggota tanpa nama pada kolom yang dideklarasikan nama TEXT NOT NULL.

sql Contoh: pelanggaran NOT NULL
CREATE TABLE anggota (
    id    INTEGER PRIMARY KEY,
    nama  TEXT NOT NULL,
    email TEXT UNIQUE
);

INSERT INTO anggota (id, email) VALUES (1, '[email protected]');
text Keluaran
Error near line 7: NOT NULL constraint failed: anggota.nama

Constraint DEFAULT bekerja pada arah yang berlawanan. Apabila kolom ditinggalkan pada pernyataan INSERT, SQLite mengisinya dengan nilai bawaan yang dideklarasikan. Blok berikut memasukkan dua anggota, satu tanpa kolom aktif dan satu dengan nilai eksplisit.

sql Contoh: DEFAULT mengisi kolom yang ditinggalkan
CREATE TABLE anggota (
    id    INTEGER PRIMARY KEY,
    nama  TEXT NOT NULL,
    aktif INTEGER NOT NULL DEFAULT 1
);

INSERT INTO anggota (nama) VALUES ('Dewi');

INSERT INTO anggota (nama, aktif) VALUES ('Farhan', 0);

SELECT id, nama, aktif FROM anggota;
text Keluaran
1|Dewi|1
2|Farhan|0

Baris pertama memperlihatkan nilai bawaan 1 yang terisi otomatis, sedangkan baris kedua memperlihatkan nilai eksplisit 0 yang menggantikannya. Nilai bawaan dievaluasi pada saat baris dimasukkan, bukan saat tabel dibuat. Perlu dicatat bahwa DEFAULT tidak menolak NULL yang dikirim secara eksplisit, sehingga kolom yang harus selalu terisi memerlukan kombinasi NOT NULL DEFAULT seperti pada contoh.

Pesan error NOT NULL selalu menyebut tabel dan kolom yang bermasalah, sehingga penyebabnya mudah dilacak pada definisi. Constraint ini juga berlaku saat UPDATE, bukan hanya saat INSERT, sehingga kolom yang sudah terisi tidak dapat dikosongkan kembali. Kombinasi keduanya dengan demikian menjadi pola standar untuk kolom status yang wajib terisi namun tetap nyaman ditulis.

UNIQUE dan pengecualiannya#

Constraint UNIQUE melarang dua baris bernilai sama pada kolomnya. Pelanggaran pertama menghasilkan error yang menyebut kolom tersebut, sebagaimana ketika dua anggota mencoba memakai alamat surel yang sama.

sql Contoh: pelanggaran UNIQUE
CREATE TABLE anggota (
    id    INTEGER PRIMARY KEY,
    nama  TEXT NOT NULL,
    email TEXT UNIQUE
);

INSERT INTO anggota (nama, email) VALUES ('Budi', '[email protected]');

INSERT INTO anggota (nama, email) VALUES ('Citra', '[email protected]');
text Keluaran
Error near line 9: UNIQUE constraint failed: anggota.email

Constraint ini memiliki satu pengecualian yang dikenal luas, yaitu NULL tidak dianggap sama dengan NULL. Beberapa baris dengan NULL pada kolom UNIQUE tetap diterima, karena perbandingan terhadap NULL tidak menghasilkan nilai benar.

sql Contoh: beberapa NULL pada kolom UNIQUE
CREATE TABLE anggota (
    id    INTEGER PRIMARY KEY,
    nama  TEXT NOT NULL,
    email TEXT UNIQUE
);

INSERT INTO anggota (nama, email) VALUES ('Dewi', NULL), ('Eka', NULL);

SELECT id, nama, email FROM anggota;
text Keluaran
1|Dewi|
2|Eka|

Pada keluaran, posisi surel yang kosong menandakan NULL, dan kedua baris tetap diterima meskipun keduanya tidak mempunyai surel. Perilaku ini mengikuti semantik perbandingan SQL, yang menyatakan bahwa perbandingan apa pun dengan NULL tidak menghasilkan nilai benar. Kolom UNIQUE dengan demikian cocok untuk data opsional seperti surel yang boleh tidak dimiliki sebagian anggota, dan setiap nilai non-NULL yang berulang tetap ditolak.

UNIQUE juga dapat diletakkan pada tingkat tabel untuk melarang duplikasi kombinasi, misalnya UNIQUE (buku_id, anggota_id) yang membatasi satu peminjaman per pasangan buku dan anggota. Bentuk tingkat tabel ini menjadi penting ketika aturannya melibatkan lebih dari satu kolom sekaligus.

CHECK untuk aturan nilai#

Constraint CHECK mengevaluasi sebuah ekspresi pada setiap INSERT dan UPDATE, dan baris hanya diterima bila ekspresinya bernilai benar atau NULL. Ekspresi boleh melibatkan beberapa kolom pada baris yang sama, sehingga CHECK cocok untuk aturan seperti batas rentang tahun terbit. Constraint ini dapat diberi nama melalui CONSTRAINT, dan nama itulah yang muncul pada pesan errornya.

sql Contoh: pelanggaran CHECK
CREATE TABLE buku (
    id    INTEGER PRIMARY KEY,
    judul TEXT NOT NULL,
    tahun INTEGER,
    CONSTRAINT cek_tahun CHECK (tahun IS NULL OR tahun >= 1800)
);

INSERT INTO buku (judul, tahun) VALUES ('Naskah Kuno', 1700);

INSERT INTO buku (judul, tahun) VALUES ('Peta Langit', 2021);

SELECT judul, tahun FROM buku;
text Keluaran
Error near line 8: CHECK constraint failed: cek_tahun
Peta Langit|2021

Pesan error menyebut nama constraint cek_tahun, sehingga aturan yang dilanggar mudah dilacak pada definisi tabel. Ekspresi pada CHECK ditulis dengan operator perbandingan dan logika yang sama seperti klausa WHERE, sehingga tidak ada sintaks baru yang perlu dipelajari. Pemeriksaan dijalankan ulang pada setiap INSERT dan UPDATE, tidak hanya pada saat tabel dibuat.

Apabila ekspresinya menghasilkan NULL karena kolom yang dirujuk belum terisi, baris tetap diterima, sebab NULL diperlakukan sama dengan hasil yang benar oleh constraint ini. Klausa tahun IS NULL OR pada contoh sengaja melonggarkan aturan untuk tahun yang belum diketahui, karena tanpa klausa tersebut setiap baris tanpa tahun akan ditolak. Baris kedua dengan tahun 2021 lolos pemeriksaan dan tersimpan seperti terlihat pada keluaran.

Perbedaan UNIQUE dan PRIMARY KEY#

Keduanya mencegah duplikasi, tetapi perannya berbeda. PRIMARY KEY menandai pengenal utama baris, sedangkan UNIQUE hanya menegakkan keunikan pada kolom biasa. Perbedaan praktisnya dirangkum pada tabel berikut.

AspekPRIMARY KEYUNIQUE
Peranpengenal utama barismencegah duplikasi pada kolom biasa
Jumlah per tabelsatubeberapa boleh
Nilai NULLtidak pernah tersimpan, nilai kosong diisi otomatis pada INTEGER PRIMARY KEYditerima, bahkan pada beberapa baris

Ada satu keanehan yang wajib diketahui. Menurut standar SQL, PRIMARY KEY seharusnya berarti NOT NULL, tetapi pada tabel biasa SQLite masih menerimanya untuk kolom yang bukan INTEGER PRIMARY KEY. Perilaku ini merupakan warisan versi lama yang dipertahankan demi kompatibilitas.

sql Contoh: NULL pada PRIMARY KEY non-integer
CREATE TABLE rak (
    kode   TEXT PRIMARY KEY,
    lantai INTEGER NOT NULL
);

INSERT INTO rak (kode, lantai) VALUES (NULL, 1);

INSERT INTO rak (kode, lantai) VALUES (NULL, 2);

SELECT quote(kode), lantai FROM rak;
text Keluaran
NULL|1
NULL|2

Kedua baris dengan kode bernilai NULL diterima, sehingga pengenal rak yang seharusnya unik kehilangan maknanya. Pada tabel strict dan tabel WITHOUT ROWID, keanehan ini sudah dihilangkan dan PRIMARY KEY menolak NULL.

Ringkasan#

  • INTEGER PRIMARY KEY menjadi alias rowid dan mengisi nilainya secara otomatis bila dibiarkan kosong.
  • NOT NULL dan CHECK menolak baris yang melanggar aturan, sedangkan DEFAULT mengisi kolom yang ditinggalkan pada INSERT.
  • UNIQUE melarang duplikasi tetapi menerima beberapa NULL, dan PRIMARY KEY non-integer pada tabel biasa berperilaku sama karena perilaku lama yang dipertahankan.

Referensi#