Apa Sebenarnya Fungsi Primary Key
Primary key adalah kolom (atau kombinasi kolom) yang mengidentifikasi setiap baris dalam tabel secara unik. Dua baris tidak boleh punya nilai primary key yang sama. SQLite menjaga aturan itu untukmu, dan memakai key tersebut untuk menemukan baris dengan cepat.
Bentuk paling sederhananya ditulis langsung pada sebuah kolom:
Kamu tidak memberikan id, dan SQLite mengisinya sendiri. Itu bukan sihir, melainkan kasus khusus untuk INTEGER PRIMARY KEY yang perlu kamu pahami sebelum menulis apa pun lagi.
INTEGER PRIMARY KEY Itu Istimewa
Di kebanyakan database, primary key hanyalah sebuah unique index. Di SQLite, setiap tabel biasa sudah punya integer 64-bit tersembunyi bernama rowid yang mengidentifikasi baris secara internal. Jika kamu mendeklarasikan sebuah kolom persis sebagai INTEGER PRIMARY KEY, kolom itu menjadi rowid. Tanpa index tambahan, tanpa penyimpanan tambahan: id-mu dan lokasi fisik barisnya adalah hal yang sama.
id dan rowid adalah kolom yang sama dengan dua nama. Pencarian berdasarkan id langsung menuju barisnya, tanpa pohon kedua yang harus ditelusuri. Itulah sebabnya saran standar untuk SQLite adalah: jika kamu ingin primary key numerik, tulis persis INTEGER PRIMARY KEY. Bukan INT, bukan BIGINT, bukan INTEGER NOT NULL PRIMARY KEY (sebenarnya yang itu berfungsi, tapi tipenya harus INTEGER).
Tipe lain tetap berfungsi, hanya saja mendapat unique index terpisah. Itu tidak masalah, hanya tidak seringkas tadi.
AUTOINCREMENT Biasanya Tidak Diperlukan
Refleks yang umum dari database lain adalah menulis id INTEGER PRIMARY KEY AUTOINCREMENT. Di SQLite, kata kunci AUTOINCREMENT melakukan sesuatu yang lebih sempit dari yang disiratkan namanya, dan sering kali kamu tidak membutuhkannya.
Tanpa AUTOINCREMENT, kolom INTEGER PRIMARY KEY otomatis diisi dengan nilai satu lebih besar dari rowid terbesar yang ada. Jika kamu menghapus baris terakhir, insert berikutnya mungkin memakai ulang id itu.
Dengan AUTOINCREMENT, SQLite mencatat id tertinggi yang pernah dipakai di tabel pendamping bernama sqlite_sequence dan tidak pernah memakai ulang nilainya, bahkan setelah dihapus.
Tabel plain memakai ulang id 3. Tabel dengan AUTOINCREMENT melompat ke 4. Kecuali kamu punya alasan nyata untuk melarang pemakaian ulang id, misalnya audit atau referensi eksternal yang masih tersisa setelah penghapusan, lewati saja AUTOINCREMENT. Fitur itu menambah satu penulisan di setiap insert dan butuh tabel pencatatan terpisah.
Primary Key Komposit
Terkadang satu kolom saja tidak cukup. Tabel penghubung yang memetakan pengguna ke peran, misalnya, diidentifikasi secara unik oleh pasangan (user_id, role_id). Untuk itu, deklarasikan key-nya di level tabel:
Pasangannya harus unik di seluruh tabel: (1, 10) hanya boleh muncul sekali. Masing-masing kolom secara terpisah boleh berulang dengan bebas. Itulah intinya: setiap pengguna bisa punya banyak peran, setiap peran bisa dimiliki banyak pengguna, tapi pasangan pengguna dan peran tertentu paling banyak hanya ada sekali.
Primary key komposit membuat index terpisah yang mencakup kolom-kolom yang disebutkan. Key itu tidak menjadi rowid; hanya satu INTEGER PRIMARY KEY yang mendapat perlakuan itu.
Jebakan NULL di Primary Key
Inilah keanehan yang mengejutkan orang yang datang dari PostgreSQL atau MySQL: di tabel SQLite biasa, kolom primary key selain INTEGER PRIMARY KEY bisa berisi NULL. Ini bug lama yang sengaja dipertahankan pembuat SQLite demi kompatibilitas ke belakang.
Dua baris dengan NULL lolos melewati primary key. Solusinya adalah menambahkan NOT NULL secara eksplisit di setiap kolom primary key yang bukan integer:
Atau pakai tabel STRICT, yang sudah memperbaiki bug NULL di primary key ini. Kebiasaan menulis NOT NULL di setiap kolom primary key adalah asuransi yang murah.
Primary Key vs UNIQUE
Keduanya mencegah duplikat. Perbedaannya:
- Sebuah tabel punya paling banyak satu primary key, tapi bisa punya banyak constraint
UNIQUE. - Primary key adalah identitas "utama" tabel: foreign key merujuk ke sana secara default.
INTEGER PRIMARY KEYmenjadi rowid; kolom integerUNIQUEtidak.- Kolom
UNIQUEdengan senang hati menerima banyakNULL(setiap NULL dianggap berbeda).
id adalah identitas baris itu. email dan username juga unik, tapi keduanya adalah atribut bisnis: nilainya bisa berubah, sedangkan id seharusnya tidak.
Menambahkan Primary Key Belakangan (Sebisa Mungkin: Jangan)
ALTER TABLE di SQLite terbatas. Kamu tidak bisa menjalankan ALTER TABLE ... ADD PRIMARY KEY, karena pernyataan itu tidak ada. Jika kamu lupa membuat primary key dan tabelnya sudah berisi data, jalannya adalah membuat ulang tabel itu:
Inilah langkah-langkah migrasi standar di SQLite. Di kode sungguhan, bungkus dalam transaksi, dan matikan foreign key sebentar jika ada tabel lain yang merujuk ke tabel ini. Pelajarannya: tentukan primary key dengan benar sejak CREATE TABLE.
Daftar Periksa Singkat
Saat menulis tabel baru, tanyakan:
- Apakah baris ini punya id unik yang alami? Jika berupa satu integer, pakai
INTEGER PRIMARY KEY. - Apakah identitasnya sebenarnya kombinasi beberapa kolom (tabel penghubung)? Pakai
PRIMARY KEY (col_a, col_b)di level tabel. - Apakah key-nya teks atau tipe lain yang bukan integer? Tambahkan
NOT NULLsecara eksplisit. - Apakah kamu benar-benar butuh
AUTOINCREMENT? Kemungkinan besar tidak. - Apakah tabelnya kecil, lebih sering dibaca, dan punya primary key non-integer? Pertimbangkan
WITHOUT ROWID(dibahas bersama dokumen rowid).
Selanjutnya: rowid
INTEGER PRIMARY KEY sempat muncul sebentar sebagai "alias untuk rowid", tapi rowid adalah fondasi di bawah setiap tabel SQLite biasa, dan layak dipahami secara langsung. Itulah topik halaman berikutnya.
Pertanyaan yang sering diajukan
Bagaimana cara mendefinisikan primary key di SQLite?
Tambahkan PRIMARY KEY ke sebuah kolom di pernyataan CREATE TABLE, misalnya id INTEGER PRIMARY KEY. Untuk key yang mencakup beberapa kolom, pakai constraint di level tabel: PRIMARY KEY (col_a, col_b). Kolom atau kombinasi kolom itu harus unik di seluruh baris.
Apa perbedaan INTEGER PRIMARY KEY dengan primary key lain di SQLite?
INTEGER PRIMARY KEY itu istimewa: kolom ini menjadi alias untuk rowid bawaan tabel, sehingga disimpan langsung di B-tree tanpa index tambahan. Tipe lain apa pun, atau key komposit, mendapat unique index terpisah. Untuk id numerik satu kolom, INTEGER PRIMARY KEY lebih cepat dan lebih kecil.
Apakah primary key SQLite butuh AUTOINCREMENT?
Biasanya tidak. INTEGER PRIMARY KEY sudah otomatis memberi rowid yang unik saat kamu memasukkan NULL. AUTOINCREMENT hanya menambahkan jaminan bahwa id tidak pernah dipakai ulang setelah dihapus, dengan biaya tabel sqlite_sequence tambahan. Lewati saja kecuali kamu memang butuh perilaku id yang selalu naik itu.
Kenapa primary key SQLite saya mengizinkan nilai NULL?
Bug lama yang dipertahankan demi kompatibilitas: di tabel biasa, kolom primary key yang bukan INTEGER bisa menerima NULL kecuali kamu menambahkan NOT NULL secara eksplisit. Kolom INTEGER PRIMARY KEY adalah pengecualiannya, karena tidak pernah mengizinkan NULL. Agar aman, tulis NOT NULL di setiap kolom primary key, atau pakai tabel STRICT yang menegakkan aturan ini dengan benar.