Affinity Adalah Preferensi, Bukan Aturan
Tipe data di SQLite bersifat dinamis. Sebuah nilai membawa storage class-nya sendiri (NULL, INTEGER, REAL, TEXT, BLOB), dan tipe yang dideklarasikan pada kolom tidak benar-benar membatasi apa yang bisa kamu masukkan ke dalamnya. Yang dilakukan tipe yang dideklarasikan adalah memberi kolom sebuah affinity, yaitu storage class pilihan yang menjadi tujuan konversi nilai yang masuk.
Lihat apa yang terjadi saat affinity tidak cukup untuk mencegah ketidakcocokan:
Baris kedua menyimpan string 'two' di kolom INTEGER. SQLite mencoba mengonversi 'two' menjadi angka, tidak bisa (itu bukan angka), dan tetap menyimpannya sebagai TEXT. typeof() memperlihatkan storage class sebenarnya dari setiap nilai, dan hasilnya tidak selalu sesuai dengan deklarasi kolom.
Ini mengejutkan orang yang datang dari Postgres atau MySQL. Tapi memang begitulah rancangannya.
Lima Affinity
Setiap kolom di tabel non-STRICT mendapat tepat satu dari berikut ini:
TEXT: mengutamakan string.NUMERIC: mengutamakan angka, tapi menerima teks jika tidak bisa dikonversi.INTEGER: sepertiNUMERIC, tapi menyimpan nilai tanpa bagian pecahan sebagai integer.REAL: mengutamakan bilangan floating-point.BLOB: tanpa preferensi, menyimpan apa pun yang kamu berikan.
Affinity BLOB juga disebut "tanpa affinity": itulah yang kamu dapat saat sama sekali tidak mendeklarasikan tipe.
Input yang sama, yaitu string '42', menghasilkan lima tipe tersimpan yang berbeda. Setiap kolom mengonversi (atau tidak) sesuai affinity-nya.
Cara SQLite Memilih Affinity dari Deklarasimu
Inilah bagian yang sering menjebak: SQLite tidak punya daftar tetap tipe yang "valid". Kamu bisa menulis hampir apa saja setelah nama kolom, dan SQLite menentukan affinity-nya dengan memindai teks itu untuk mencari potongan teks, dengan urutan berikut:
- Mengandung
INT→INTEGER - Mengandung
CHAR,CLOB, atauTEXT→TEXT - Mengandung
BLOB, atau tanpa tipe sama sekali →BLOB - Mengandung
REAL,FLOA, atauDOUB→REAL - Selain itu →
NUMERIC
Itulah seluruh algoritmanya. Algoritma ini menjelaskan banyak keanehan:
FLOATING_POINTS menjadi INTEGER karena potongan teks INT muncul di POINTS. Aturan pertama yang cocok yang menang, dari atas ke bawah. Itulah sebabnya menyalin tipe dari database lain begitu saja bisa memberimu hasil yang berbeda dari dugaanmu.
Affinity dalam Praktik: Konversi Saat Insert
Affinity paling berpengaruh saat SQLite memutuskan apakah nilaimu dikonversi atau disimpan apa adanya. Aturannya:
- Affinity
TEXT: angka danBLOBdikonversi menjadi teks. - Affinity
NUMERIC,INTEGER,REAL: teks yang terlihat seperti angka dikonversi; teks yang tidak terlihat seperti angka tetap teks. - Affinity
BLOB: tidak ada yang dikonversi.
Baris demi baris:
'123'di kolomNUMERICmenjadi integer123. Konversi teks ke angka berhasil tanpa kehilangan informasi.'12.5'menjadi real12.5.'hello'diNUMERICtetap sebagai teks, karena tidak ada angka yang bisa dihasilkan.- Kolom
TEXTmengonversi angka menjadi bentuk string-nya. - Kolom
BLOBmenyimpan semuanya persis seperti yang diberikan, termasuk tipenya.
Keunikan INTEGER vs REAL
Affinity INTEGER berperilaku hampir sama dengan NUMERIC, dengan satu perbedaan: nilai seperti 3.0 yang tidak punya bagian pecahan sungguhan disimpan sebagai integer 3 untuk menghemat ruang.
3.0 tersimpan sebagai INTEGER di kedua kolom, karena optimasi ini juga terjadi untuk NUMERIC. 3.5 mempertahankan bagian pecahannya dan tetap REAL. Pelajarannya: jangan mengandalkan typeof() untuk mengetahui apakah sebuah kolom dideklarasikan INTEGER atau REAL. Fungsi itu memberi tahu apa yang benar-benar tersimpan, dan itu bisa berbeda dari baris ke baris.
Saat Affinity Menjadi Masalah
Fleksibilitas ini nyaman, sampai suatu saat tidak lagi. Ada dua bentuk kegagalan yang muncul di kode sungguhan:
1. Data buruk menyelinap masuk. Jika aplikasimu punya bug yang mengirim 'N/A' ke kolom INTEGER, SQLite tetap menyimpannya. Query berikutnya yang melakukan aritmetika pada kolom itu mengembalikan hasil aneh atau NULL. Tanpa error, tanpa peringatan, hanya kerusakan data yang diam-diam.
2. Perbandingan jadi aneh. Pengurutan dan pemeriksaan kesamaan memperlakukan nilai dengan storage class berbeda secara berbeda pula:
Integer diurutkan secara numerik, lalu nilai teks diurutkan secara leksikografis, dan semuanya diletakkan setelah semua angka. Jadi kamu mendapat 2, 3, 10 (integer dalam urutan numerik), lalu '20', '100' (string dalam urutan abjad). Bukan itu yang diinginkan kebanyakan orang.
Jika kamu mengendalikan insert dan memvalidasinya dengan cermat, tabel biasa tidak masalah. Jika tidak, atau kamu memang ingin database yang menegakkan tipe untukmu, ada pilihan yang lebih baik.
Berikutnya: Tabel STRICT
SQLite 3.37 menambahkan tabel STRICT, yang mematikan affinity dan menolak nilai yang tidak cocok dengan tipe yang dideklarasikan. Dengan begitu kamu mendapat perilaku tipe data dinamis secara default saat kamu menginginkannya, dan penegakan ala Postgres saat kamu tidak menginginkannya. Itu halaman berikutnya.
Pertanyaan yang sering diajukan
Apa itu type affinity di SQLite?
Type affinity adalah storage class yang diutamakan untuk sebuah kolom. SQLite punya lima: TEXT, NUMERIC, INTEGER, REAL, dan BLOB. Saat kamu memasukkan nilai, SQLite mencoba mengonversinya ke affinity kolom itu, tapi jika konversinya akan menghilangkan informasi atau tidak mungkin dilakukan, nilai disimpan apa adanya. Affinity adalah petunjuk, bukan constraint yang mengikat.
Bagaimana SQLite menentukan affinity sebuah kolom?
SQLite memindai nama tipe yang kamu tulis di CREATE TABLE untuk mencari potongan teks, berurutan: jika mengandung INT, hasilnya INTEGER; jika tidak, CHAR, CLOB, atau TEXT membuatnya TEXT; jika tidak, BLOB (atau tanpa tipe) membuatnya BLOB; jika tidak, REAL, FLOA, atau DOUB membuatnya REAL; selain itu NUMERIC. Itulah sebabnya VARCHAR(50) menjadi TEXT dan BIGINT menjadi INTEGER: kata yang kamu tulis dicocokkan polanya.
Bisakah kolom SQLite menampung nilai dengan tipe yang salah?
Bisa, di tabel biasa. Kolom yang dideklarasikan INTEGER dengan senang hati menyimpan string 'hello' karena affinity hanya menyarankan konversi. Kalau kamu mau penegakan tipe yang ketat, pakai tabel STRICT, yang langsung menolak nilai yang tidak cocok. Kita membahasnya berikutnya.