UNIQUE Berarti "Duplikat Tidak Diizinkan"
Constraint UNIQUE memberi tahu SQLite bahwa nilai dalam sebuah kolom (atau sekelompok kolom) tidak boleh berulang antarbaris. Dengan constraint inilah kamu menyatakan "dua user tidak boleh memakai email yang sama" atau "kode produk muncul paling banyak sekali."
Insert ketiga gagal dengan UNIQUE constraint failed: users.email. SQLite memeriksa constraint pada setiap penulisan dan menolak apa pun yang akan menghasilkan duplikat. Dua baris pertama tersimpan; baris ketiga tidak pernah masuk.
Di balik layar, UNIQUE diimplementasikan sebagai unique index, struktur data yang sama yang dipakai SQLite untuk pencarian cepat, jadi pemeriksaannya murah dan kolomnya otomatis ter-index.
Sintaks Tingkat Kolom vs Tingkat Tabel
Ada dua cara menulis UNIQUE: langsung di samping kolom, atau sebagai klausa terpisah di akhir definisi tabel:
Untuk satu kolom, keduanya setara, jadi pilih yang lebih enak dibaca. Bentuk tingkat tabel menjadi wajib begitu kamu butuh keunikan di lebih dari satu kolom.
UNIQUE Komposit: Beberapa Kolom Sekaligus
Kadang satu kolom tidak unik dengan sendirinya, tapi kombinasinya harus unik. Seorang user bisa mendaftar di banyak kursus, dan satu kursus bisa punya banyak user, tapi pasangan (user_id, course_id) yang sama tidak boleh muncul dua kali:
Constraint-nya berlaku pada pasangan, bukan pada salah satu kolom saja. User 1 bisa mendaftar di banyak kursus, kursus 100 bisa punya banyak user, tapi hanya sekali untuk setiap kombinasi.
Ini pola andalan untuk tabel penghubung pada relasi many-to-many.
UNIQUE vs PRIMARY KEY
Keduanya terdengar mirip dan memang berhubungan, tapi bukan hal yang sama:
- Sebuah tabel punya paling banyak satu
PRIMARY KEY. Tabel itu bisa punya banyak constraintUNIQUE. PRIMARY KEYadalah identitas baris: yang dituju oleh foreign key, dan yang dialiaskan olehrowid.UNIQUEhanya berarti "nilai (atau kombinasi) ini tidak berulang."- Di tabel biasa, kolom
UNIQUEbisa menampung nilaiNULL;PRIMARY KEYtidak bisa (dengan satu pengecualian historis yang tidak kita bahas).
Bentuk yang umum:
id adalah yang dirujuk oleh bagian lain database. email dan username unik karena aplikasi mengharuskannya, bukan karena keduanya identitas. Jika user mengganti email-nya, id-nya tetap sama, dan itulah gunanya memisahkan keduanya.
Keanehan NULL
Hal ini menjebak hampir semua orang di kali pertama. Kolom UNIQUE di SQLite menerima nilai NULL sebanyak yang kamu mau:
Tiga NULL, tidak masalah. Dua 'ada@example.com', itu konflik.
Alasannya: SQL memperlakukan NULL sebagai "tidak diketahui", dan dua hal yang tidak diketahui tidak dianggap sama, sehingga pemeriksaan keunikan tidak bisa menyatakan keduanya duplikat. Jika kamu butuh paling banyak satu NULL, solusi paling rapi adalah NOT NULL UNIQUE. Jika NULL boleh ada tapi hanya satu untuk setiap kombinasi kolom lain, pakai partial index (dibahas nanti di bab index).
Menangani Konflik: ON CONFLICT
Secara default, pelanggaran UNIQUE membatalkan pernyataan. Tapi kadang kamu ingin perilaku lain: mengganti baris yang ada, mengabaikan baris baru, atau memperbarui kolom tertentu. SQLite memberimu dua cara untuk memintanya.
Cara pertama dipasang langsung pada constraint dengan ON CONFLICT:
Saat theme dimasukkan untuk kedua kalinya, baris yang ada dihapus dan baris baru menggantikannya. Pilihan lainnya adalah IGNORE (lewati diam-diam), ABORT (default), FAIL, dan ROLLBACK.
Cara kedua berlaku per pernyataan, dengan sintaks upsert. Cara ini biasanya lebih fleksibel karena bisa memperbarui kolom tertentu:
Insert pertama membuat barisnya. Dua insert berikutnya menabrak constraint UNIQUE dan jatuh ke cabang DO UPDATE, sehingga count bertambah. Inilah pola upsert INSERT ... ON CONFLICT, yang punya halaman khusus nanti.
Constraint UNIQUE vs Unique Index
CREATE UNIQUE INDEX mengerjakan tugas yang sama dengan constraint UNIQUE. Bahkan, constraint UNIQUE membuat unique index di balik layar: keduanya hampir merupakan mekanisme yang sama dengan nama yang berbeda.
Kapan memilih yang mana:
- Constraint saat keunikan adalah bagian dari definisi tabel. Aturannya terdokumentasi tepat di samping kolom-kolomnya.
- Unique index saat kamu ingin partial index (klausa
WHERE), butuh nama tertentu, atau ingin menambahkannya ke tabel yang sudah ada tanpa menulis ulang tabel itu.ALTER TABLEdi SQLite tidak bisa menambahkan constraint, tapi index selalu bisa ditambahkan.
Perilakunya saat penulisan sama persis. Pilihannya lebih tentang di mana kamu ingin aturan itu berada dalam skema.
Menambahkan UNIQUE ke Tabel yang Sudah Ada
ALTER TABLE di SQLite sengaja dibuat terbatas: tidak ada ALTER TABLE ... ADD CONSTRAINT. Dua pilihan praktisnya:
Pilihan kedua, saat kamu benar-benar ingin klausa UNIQUE tertanam di definisi tabel, adalah ritual menulis ulang tabel: buat tabel baru dengan constraint itu, salin datanya, hapus tabel lama, lalu ganti namanya. Ini dibahas di halaman berikutnya.
Sebagai peringatan: jika kamu menambahkan keunikan ke kolom yang sudah berisi duplikat, CREATE UNIQUE INDEX akan gagal. Bersihkan dulu baris duplikatnya, baru tambahkan index-nya.
Saat UNIQUE Gagal: Membaca Error-nya
Pesan error memberi tahu dengan tepat constraint mana yang gagal:
Error: UNIQUE constraint failed: users.email
Error: UNIQUE constraint failed: enrollments.user_id, enrollments.course_id
Bentuk pertama adalah constraint satu kolom pada users.email. Yang kedua adalah komposit: kedua kolom dicantumkan karena kombinasinya sudah ada. Saat kamu melihat ini:
- Temukan baris mana yang sudah punya nilai yang berkonflik (
SELECT ... WHERE email = '...'). - Putuskan apakah kamu ingin memperbarui baris itu, melewati insert, atau memakai nilai lain.
- Jika duplikat memang diharapkan dan kamu ingin menggabungkannya, beralihlah ke
INSERT ... ON CONFLICT DO UPDATE.
Error-nya lantang karena sebagian besar waktu kamu memang ingin tahu: duplikat yang diam-diam masuk lebih buruk daripada penulisan yang gagal.
Berikutnya: Menghapus dan Mengubah Tabel
Constraint UNIQUE tidak bisa ditambahkan ke tabel yang sudah ada dengan ALTER TABLE sederhana. Keterbatasan itulah alasan SQLite punya ritual khusus untuk perubahan skema, yaitu menulis ulang tabel, dan itu topik halaman berikutnya, bersama dasar-dasar menghapus tabel dengan bersih.
Pertanyaan yang sering diajukan
Bagaimana cara menambahkan constraint UNIQUE di SQLite?
Tambahkan UNIQUE pada definisi kolom (email TEXT UNIQUE) atau tulis klausa UNIQUE(col1, col2) di tingkat tabel untuk keunikan beberapa kolom. SQLite menegakkannya dengan membuat unique index di balik layar dan menolak setiap INSERT atau UPDATE yang akan menghasilkan duplikat.
Apa perbedaan UNIQUE dan PRIMARY KEY di SQLite?
Sebuah tabel hanya bisa punya satu PRIMARY KEY, tapi bisa punya banyak constraint UNIQUE. PRIMARY KEY juga berarti NOT NULL (di tabel strict dan untuk INTEGER PRIMARY KEY), sedangkan kolom UNIQUE bisa menampung banyak nilai NULL. Pakai primary key untuk identitas baris, dan UNIQUE untuk kolom lain yang tidak boleh terduplikasi.
Kenapa SQLite mengizinkan banyak NULL di kolom UNIQUE?
Karena SQL memperlakukan NULL sebagai 'tidak diketahui', dan dua hal yang tidak diketahui tidak dianggap sama. Jadi kolom UNIQUE menerima baris NULL sebanyak yang kamu mau; hanya nilai yang bukan NULL yang harus berbeda. Jika kamu butuh paling banyak satu NULL, tambahkan NOT NULL atau pakai partial unique index.
Bagaimana cara memperbaiki error 'UNIQUE constraint failed'?
Error itu berarti sebuah INSERT atau UPDATE akan membuat nilai duplikat di kolom UNIQUE (atau PRIMARY KEY). Ubah nilai yang kamu masukkan, hapus dulu baris yang sudah ada, atau pakai INSERT ... ON CONFLICT (upsert) untuk memberi tahu SQLite apa yang harus dilakukan saat konflik terjadi.