Generated Column Adalah Kolom Hasil Perhitungan
Generated column adalah kolom yang nilainya berasal dari sebuah ekspresi, bukan dari INSERT. Kamu mendeklarasikan rumusnya sekali di CREATE TABLE, dan SQLite mengurus sisanya. Kamu tidak pernah menulis ke kolom itu; mencobanya akan menghasilkan error.
Contoh sesingkat mungkin:
total tidak pernah di-insert, tapi muncul di setiap baris. SQLite menghitung ulang nilainya dari price + tax setiap kali kamu membaca baris itu. Perbarui salah satu kolom, dan total ikut berubah.
Frasa kata kunci GENERATED ALWAYS AS wajib ditulis. ALWAYS hanyalah formalitas standar SQL, karena tidak ada pilihan lain di SQLite.
VIRTUAL vs STORED
Setiap generated column termasuk salah satu dari dua jenis. Bawaannya adalah VIRTUAL:
Gambaran sederhananya:
VIRTUAL: memakan nol byte di disk, memakan CPU setiap kali dibaca. Murah untuk ditambahkan, murah untuk diubah nanti.STORED: memakan ruang disk, tidak ada biaya tambahan saat dibaca. Sepadan kalau ekspresinya mahal atau kolomnya jauh lebih sering dibaca daripada ditulis.
Kalau kamu tidak menulis kata kunci, kamu mendapat VIRTUAL. Itu hampir selalu pilihan bawaan yang tepat.
Kenapa Repot? Nilai Turunan yang Bisa Di-index
Fitur andalannya adalah kamu bisa memasang index pada generated column. Dengan begitu kamu mendapat pencarian yang cepat pada nilai turunan tanpa menulis ulang setiap query.
Misalnya kamu ingin mencari email tanpa membedakan huruf besar kecil:
Index-nya mencakup bentuk huruf kecil. Query yang memfilter email_lower langsung memakai index itu. SQLite sebenarnya juga punya expression index (CREATE INDEX ... ON users(lower(email))), tapi generated column membuat nilai turunan itu terlihat sebagai kolom sungguhan yang bisa kamu SELECT, rujuk di view, dan pakai ulang dari kode aplikasi.
Mengambil Nilai dari JSON
Generated column bersinar di atas JSON. Dukungan JSON di SQLite menyediakan ->> untuk mengambil nilai skalar; bungkus itu dalam generated column, dan kamu mendapat field bertipe yang bisa di-index di atas blob yang fleksibel.
user_id dan kind terlihat seperti kolom biasa bagi query-mu, tapi datanya tersimpan di payload. Ubah JSON-nya, dan kolom-kolom itu ikut diperbarui. Index pada user_id membuat pencariannya cepat.
Aturan dan Batasan
Beberapa hal yang ditegakkan SQLite, dan sebaiknya kamu tahu sebelum menabraknya:
- Ekspresinya harus deterministik.
random(),datetime('now'), dan fungsi non-deterministik lainnya tidak diizinkan. Nilainya harus bisa dihasilkan ulang dari baris itu. - Ekspresinya hanya boleh merujuk kolom di baris yang sama. Tidak boleh ada subquery, agregat, atau tabel lain.
- Kamu tidak bisa melakukan
INSERTatauUPDATElangsung ke generated column.INSERT INTO products (total) VALUES (5)adalah error. - Kolom
STOREDtidak bisa ditambahkan denganALTER TABLE ... ADD COLUMN. HanyaVIRTUALyang bisa ditambahkan belakangan. - Generated column boleh punya constraint
NOT NULL,CHECK,UNIQUE, bahkanFOREIGN KEY. Untuk keperluan itu, perilakunya sama seperti kolom lain.
Demo singkat aturan penulisannya:
sqlite> INSERT INTO products (price, tax, total) VALUES (10, 1, 999);
Runtime error: cannot INSERT into generated column "total"
Perbaikannya adalah mengeluarkan generated column dari daftar kolom INSERT dan membiarkan SQLite yang menghitungnya.
Memilih VIRTUAL atau STORED
Keputusannya biasanya bergantung pada perbandingan baca dan tulis serta biaya ekspresinya:
Patokan praktisnya:
- Pakai
VIRTUALsebagai bawaan. Gratis saat penulisan dan cocok untuk hampir semua hal. - Ganti ke
STOREDkalau kamu memasang index pada kolom itu di tabel yang sering ditulisi (index-nya toh butuh nilai yang tersimpan), atau kalau ekspresinya memang mahal. - Jangan terlalu dipusingkan. Jenisnya memang bagian dari skema, tapi kamu bisa menghapus dan membuat ulang kolomnya kalau berubah pikiran, setidaknya untuk
VIRTUAL.
Generated Column vs View
Ada tumpang tindih dengan view: keduanya menampilkan nilai hasil perhitungan tanpa menyimpannya (yah, kadang-kadang). Pembagiannya biasanya seperti ini:
- Generated column milik satu baris dan satu tabel. Pakai untuk turunan per baris: memformat email, mengambil field JSON, menghitung total.
- View adalah query yang disimpan. Pakai kalau perhitungannya melibatkan join, agregasi, atau penyaringan lintas baris.
Kamu bisa menggabungkan keduanya. Sebuah view bisa melakukan SELECT dari tabel yang punya generated column lalu menambahkan konteks lewat join. Generated column berada di lapisan penyimpanan; view berada di lapisan query.
Berikutnya: ATTACH DATABASE
Generated column memungkinkan satu tabel menghitung nilainya sendiri. Halaman berikutnya bergerak ke arah sebaliknya: menghubungkan beberapa database SQLite sekaligus dengan ATTACH DATABASE, sehingga satu query bisa menjangkau beberapa file.
Pertanyaan yang sering diajukan
Apa itu generated column di SQLite?
Generated column adalah kolom yang nilainya dihitung dari sebuah ekspresi yang melibatkan kolom lain di baris yang sama. Kamu mendeklarasikannya dengan GENERATED ALWAYS AS (expression) di CREATE TABLE. Kamu tidak pernah menulis ke kolom itu secara langsung: SQLite yang menghitungnya untukmu setiap kali baris dibaca atau disimpan.
Apa bedanya generated column VIRTUAL dan STORED?
Kolom VIRTUAL dihitung setiap kali dibaca dan tidak memakan ruang di disk; ini bawaannya. Kolom STORED dihitung sekali saat ditulis dan disimpan di file database, sehingga pembacaan lebih murah tapi penulisan sedikit lebih mahal. Keduanya bisa diberi index, tapi STORED biasanya pilihan yang tepat kalau ekspresinya berat atau kolomnya jauh lebih sering dibaca daripada ditulis.
Bisakah generated column di SQLite diberi index?
Bisa. CREATE INDEX bekerja pada generated column, baik VIRTUAL maupun STORED. Inilah alasan utama memakainya: kamu bisa membuat index untuk nilai turunan (seperti lower(email) atau field JSON yang diambil dengan ->>) dan membiarkan query planner memakai index itu tanpa harus menulis ulang setiap query.
Bisakah ALTER TABLE dipakai untuk menambahkan generated column?
Bisa, tapi hanya untuk kolom VIRTUAL. ALTER TABLE ... ADD COLUMN ... GENERATED ALWAYS AS (...) VIRTUAL berjalan tanpa masalah. Menambahkan generated column STORED dengan ALTER TABLE tidak didukung, jadi kamu harus membangun ulang tabelnya. Rencanakan dari awal kalau kamu ingin kolom stored pada tabel yang sudah ada.